ai重构ok

This commit is contained in:
aozhiwei 2021-06-08 19:54:24 +08:00
parent 1036102409
commit ee0005663c
7 changed files with 237 additions and 222 deletions

View File

@ -1,5 +1,10 @@
#pragma once #pragma once
namespace MetaData
{
class AI;
}
class MoveableEntity; class MoveableEntity;
class AIComponent class AIComponent
{ {

View File

@ -18,6 +18,52 @@ enum ShotType_e
kShotHold = 2, kShotHold = 2,
}; };
enum AndroidState_e : int
{
AS_thinking,
AS_moving,
AS_attack
};
enum AndroidStateEx_e : int
{
ASE_Idle = 0,
ASE_Thinking = 1,
ASE_Attack = 2,
ASE_RandomWalk = 3,
ASE_Pursuit = 4
};
class Human;
class AINode
{
public:
AndroidStateEx_e main_state = ASE_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;
CreatureWeakPtr target;
CreatureWeakPtr nearest_human;
long long last_check_nearest_human_frameno = 0;
a8::Vec2 shot_dir;
};
struct OldAiData
{
AndroidState_e state = AS_thinking;
int state_elapsed_time = 0;
CreatureWeakPtr last_target;
long long last_attack_frameno = 0;
long long last_findenemy_frameno = 0;
long long series_attack_frames = 0;
};
/* /*
nn目标ai可切换/() nn目标ai可切换/()
@ -32,13 +78,21 @@ ai级别
8: 8:
*/ */
AndroidNewAI::AndroidNewAI()
{
old_ai_data_ = new OldAiData();
node_ = new AINode();
}
AndroidNewAI::~AndroidNewAI() AndroidNewAI::~AndroidNewAI()
{ {
A8_SAFE_DELETE(old_ai_data_);
A8_SAFE_DELETE(node_);
} }
void AndroidNewAI::Update(int delta_time) void AndroidNewAI::Update(int delta_time)
{ {
old_ai_data_.state_elapsed_time += delta_time; old_ai_data_->state_elapsed_time += delta_time;
Human* hum = (Human*)owner; Human* hum = (Human*)owner;
if (hum->poisoning) { if (hum->poisoning) {
hum->poisoning_time += delta_time; hum->poisoning_time += delta_time;
@ -67,10 +121,10 @@ float AndroidNewAI::GetAttackRate()
void AndroidNewAI::DefaultAi() void AndroidNewAI::DefaultAi()
{ {
switch (old_ai_data_.state) { switch (old_ai_data_->state) {
case AS_thinking: case AS_thinking:
{ {
if (old_ai_data_.state_elapsed_time > 1500 + rand() % 3000) { if (old_ai_data_->state_elapsed_time > 1500 + rand() % 3000) {
int rnd = rand(); int rnd = rand();
if (rnd % 100 < 30) { if (rnd % 100 < 30) {
ChangeToStateOldAI(AS_moving); ChangeToStateOldAI(AS_moving);
@ -82,7 +136,7 @@ void AndroidNewAI::DefaultAi()
break; break;
case AS_moving: case AS_moving:
{ {
if (old_ai_data_.state_elapsed_time < 1000 + rand() % 2000) { if (old_ai_data_->state_elapsed_time < 1000 + rand() % 2000) {
DoMoveOldAI(); DoMoveOldAI();
} else { } else {
int rnd = rand(); int rnd = rand();
@ -96,8 +150,8 @@ void AndroidNewAI::DefaultAi()
break; break;
case AS_attack: case AS_attack:
{ {
if ((old_ai_data_.state_elapsed_time < 3000 && old_ai_data_.last_target.Get()) || if ((old_ai_data_->state_elapsed_time < 3000 && old_ai_data_->last_target.Get()) ||
(old_ai_data_.state_elapsed_time < 1100)) { (old_ai_data_->state_elapsed_time < 1100)) {
DoAttackOldAI(); DoAttackOldAI();
} else { } else {
int rnd = rand(); int rnd = rand();
@ -114,9 +168,9 @@ void AndroidNewAI::DefaultAi()
void AndroidNewAI::ChangeToStateOldAI(AndroidState_e to_state) void AndroidNewAI::ChangeToStateOldAI(AndroidState_e to_state)
{ {
old_ai_data_.state = to_state; old_ai_data_->state = to_state;
old_ai_data_.state_elapsed_time = 0; old_ai_data_->state_elapsed_time = 0;
switch (old_ai_data_.state) { switch (old_ai_data_->state) {
case AS_moving: case AS_moving:
{ {
Human* hum = (Human*)owner; Human* hum = (Human*)owner;
@ -186,7 +240,7 @@ void AndroidNewAI::DoAttackOldAI()
bool shot_ok = false; bool shot_ok = false;
sender->Shot(shot_dir, shot_ok, DEFAULT_FLY_DISTANCE); sender->Shot(shot_dir, shot_ok, DEFAULT_FLY_DISTANCE);
} }
old_ai_data_.last_target.Attach(enemy); old_ai_data_->last_target.Attach(enemy);
} }
} }
} }
@ -206,9 +260,9 @@ void AndroidNewAI::UpdateNewAI()
if (hum->playing_skill) { if (hum->playing_skill) {
hum->UpdateSkill(); hum->UpdateSkill();
} }
++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 ASE_Idle: case ASE_Idle:
{ {
UpdateIdle(); UpdateIdle();
@ -248,7 +302,7 @@ void AndroidNewAI::UpdateNewAI()
void AndroidNewAI::UpdateIdle() void AndroidNewAI::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) {
ChangeToStateNewAI(ASE_Thinking); ChangeToStateNewAI(ASE_Thinking);
} }
} }
@ -268,10 +322,10 @@ void AndroidNewAI::UpdateThinking()
} else { } else {
Creature* target = GetTarget(); Creature* target = GetTarget();
if (target) { if (target) {
node_.target.Attach(target); node_->target.Attach(target);
ChangeToStateNewAI(ASE_Attack); ChangeToStateNewAI(ASE_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) {
ChangeToStateNewAI(ASE_Idle); ChangeToStateNewAI(ASE_Idle);
} else { } else {
@ -279,7 +333,7 @@ void AndroidNewAI::UpdateThinking()
} }
} else { } else {
ChangeToStateNewAI(ASE_Idle); ChangeToStateNewAI(ASE_Idle);
node_.param1 = node_.next_random_move_frameno - hum->room->GetFrameNo(); node_->param1 = node_->next_random_move_frameno - hum->room->GetFrameNo();
} }
} }
} }
@ -288,11 +342,11 @@ void AndroidNewAI::UpdateThinking()
void AndroidNewAI::UpdateAttack() void AndroidNewAI::UpdateAttack()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
if (!node_.target.Get() || node_.target.Get()->dead) { if (!node_->target.Get() || node_->target.Get()->dead) {
ChangeToStateNewAI(ASE_Thinking); ChangeToStateNewAI(ASE_Thinking);
return; return;
} }
if (node_.exec_frame_num > SERVER_FRAME_RATE * 8) { if (node_->exec_frame_num > SERVER_FRAME_RATE * 8) {
ChangeToStateNewAI(ASE_Thinking); ChangeToStateNewAI(ASE_Thinking);
return; return;
} }
@ -305,7 +359,7 @@ void AndroidNewAI::UpdateAttack()
if (myself->HasBuffEffect(kBET_Vertigo)) { if (myself->HasBuffEffect(kBET_Vertigo)) {
return; return;
} }
float distance = myself->GetPos().Distance(node_.target.Get()->GetPos()); float distance = myself->GetPos().Distance(node_->target.Get()->GetPos());
if (distance > GetAttackRange()) { if (distance > GetAttackRange()) {
if (ai_meta->i->pursuit_radius() <= 0) { if (ai_meta->i->pursuit_radius() <= 0) {
//站桩 //站桩
@ -325,12 +379,12 @@ void AndroidNewAI::UpdateAttack()
case kShotClick: case kShotClick:
{ {
if (ai_meta->i->attack_interval() > 0) { if (ai_meta->i->attack_interval() > 0) {
if (node_.shot_times < GetAttackTimes()) { if (node_->shot_times < GetAttackTimes()) {
DoShotNewAI(); DoShotNewAI();
} else { } else {
ChangeToStateNewAI(ASE_Idle); ChangeToStateNewAI(ASE_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 = ai_meta->i->attack_interval() / 1000 * SERVER_FRAME_RATE;
} }
} else { } else {
myself->shot_hold = true; myself->shot_hold = true;
@ -355,7 +409,7 @@ void AndroidNewAI::UpdateAttack()
void AndroidNewAI::UpdateRandomWalk() void AndroidNewAI::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) {
ChangeToStateNewAI(ASE_Thinking); ChangeToStateNewAI(ASE_Thinking);
} }
} }
@ -363,19 +417,19 @@ void AndroidNewAI::UpdateRandomWalk()
void AndroidNewAI::UpdatePursuit() void AndroidNewAI::UpdatePursuit()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
if (node_.target.Get()) { if (node_->target.Get()) {
float distance = myself->GetPos().Distance(node_.target.Get()->GetPos()); float distance = myself->GetPos().Distance(node_->target.Get()->GetPos());
if (!myself->HasBuffEffect(kBET_Jump) && if (!myself->HasBuffEffect(kBET_Jump) &&
!a8::HasBitFlag(myself->status, HS_DisableAttack) && !a8::HasBitFlag(myself->status, HS_DisableAttack) &&
distance < GetAttackRange()) { distance < GetAttackRange()) {
ChangeToStateNewAI(ASE_Attack); ChangeToStateNewAI(ASE_Attack);
} else { } else {
if (node_.exec_frame_num > 100 * 2) { if (node_->exec_frame_num > 100 * 2) {
ChangeToStateNewAI(ASE_RandomWalk); ChangeToStateNewAI(ASE_RandomWalk);
} }
} }
} else { } else {
if (node_.exec_frame_num > 100 * 2) { if (node_->exec_frame_num > 100 * 2) {
ChangeToStateNewAI(ASE_RandomWalk); ChangeToStateNewAI(ASE_RandomWalk);
} }
} }
@ -397,11 +451,11 @@ void AndroidNewAI::DoMoveNewAI()
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.Get()) { if (node_->nearest_human.Get()) {
if (node_.main_state != ASE_Pursuit && if (node_->main_state != ASE_Pursuit &&
hum->GetPos().ManhattanDistance(node_.nearest_human.Get()->GetPos()) < 200) { hum->GetPos().ManhattanDistance(node_->nearest_human.Get()->GetPos()) < 200) {
ChangeToStateNewAI(ASE_Thinking); ChangeToStateNewAI(ASE_Thinking);
} else if (hum->GetPos().ManhattanDistance(node_.nearest_human.Get()->GetPos()) > 800) { } else if (hum->GetPos().ManhattanDistance(node_->nearest_human.Get()->GetPos()) > 800) {
GetTarget(); GetTarget();
} }
} }
@ -414,57 +468,57 @@ void AndroidNewAI::ChangeToStateNewAI(AndroidStateEx_e to_state)
switch (to_state) { switch (to_state) {
case ASE_Idle: case ASE_Idle:
{ {
node_.target.Reset(); node_->target.Reset();
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; moving_ = false;
if (hum->room->GetGasData().gas_mode == GasInactive || if (hum->room->GetGasData().gas_mode == GasInactive ||
hum->room->IsWaitingStart() || hum->room->IsWaitingStart() ||
hum->HasBuffEffect(kBET_Jump)) { hum->HasBuffEffect(kBET_Jump)) {
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 ASE_Thinking: case ASE_Thinking:
{ {
node_.target.Reset(); node_->target.Reset();
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; moving_ = false;
} }
break; break;
case ASE_Attack: case ASE_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; moving_ = false;
node_.shot_times = 0; node_->shot_times = 0;
} }
break; break;
case ASE_RandomWalk: case ASE_RandomWalk:
{ {
moving_ = true; moving_ = true;
node_.target.Reset(); node_->target.Reset();
#if 1 #if 1
node_.param1 = SERVER_FRAME_RATE * ai_meta->GetMoveTime(); node_->param1 = SERVER_FRAME_RATE * 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 * ai_meta->GetMoveIdleTime();
a8::Vec2 move_dir = a8::Vec2(1.0f, 0); a8::Vec2 move_dir = a8::Vec2(1.0f, 0);
move_dir.Rotate(a8::RandAngle()); move_dir.Rotate(a8::RandAngle());
move_dir.Normalize(); move_dir.Normalize();
hum->SetMoveDir(move_dir); hum->SetMoveDir(move_dir);
hum->SetAttackDir(hum->GetMoveDir()); hum->SetAttackDir(hum->GetMoveDir());
if (node_.param1 <= 1) { if (node_->param1 <= 1) {
moving_ = false; moving_ = false;
} }
} }
@ -472,8 +526,8 @@ void AndroidNewAI::ChangeToStateNewAI(AndroidStateEx_e to_state)
case ASE_Pursuit: case ASE_Pursuit:
{ {
moving_ = true; moving_ = true;
if (node_.target.Get()) { if (node_->target.Get()) {
a8::Vec2 move_dir = node_.target.Get()->GetPos() - hum->GetPos(); a8::Vec2 move_dir = node_->target.Get()->GetPos() - hum->GetPos();
move_dir.Normalize(); move_dir.Normalize();
hum->SetMoveDir(move_dir); hum->SetMoveDir(move_dir);
hum->SetAttackDir(hum->GetMoveDir()); hum->SetAttackDir(hum->GetMoveDir());
@ -481,9 +535,9 @@ void AndroidNewAI::ChangeToStateNewAI(AndroidStateEx_e to_state)
} }
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;
} }
Creature* AndroidNewAI::GetTarget() Creature* AndroidNewAI::GetTarget()
@ -511,8 +565,8 @@ Creature* AndroidNewAI::GetTarget()
} }
}); });
if (target) { if (target) {
node_.nearest_human.Attach(target); node_->nearest_human.Attach(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;
@ -535,15 +589,15 @@ float AndroidNewAI::GetAttackRange()
void AndroidNewAI::DoShotNewAI() void AndroidNewAI::DoShotNewAI()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
if (!node_.target.Get()) { if (!node_->target.Get()) {
return; return;
} }
bool shot_ok = false; bool shot_ok = false;
a8::Vec2 shot_dir = myself->GetAttackDir(); a8::Vec2 shot_dir = myself->GetAttackDir();
if (node_.total_shot_times >= node_.next_total_shot_times) { if (node_->total_shot_times >= node_->next_total_shot_times) {
shot_dir = node_.target.Get()->GetPos() - myself->GetPos(); shot_dir = node_->target.Get()->GetPos() - myself->GetPos();
node_.next_total_shot_times += 7 + (rand() % 6); node_->next_total_shot_times += 7 + (rand() % 6);
myself->SetAttackDir(shot_dir); myself->SetAttackDir(shot_dir);
} }
if (std::abs(shot_dir.x) > FLT_EPSILON || if (std::abs(shot_dir.x) > FLT_EPSILON ||
@ -563,11 +617,11 @@ void AndroidNewAI::DoShotNewAI()
myself->Shot(shot_dir, shot_ok, DEFAULT_FLY_DISTANCE); myself->Shot(shot_dir, shot_ok, DEFAULT_FLY_DISTANCE);
myself->SetAttackDir(old_attack_dir); myself->SetAttackDir(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;
} }
} }
} }
@ -581,4 +635,3 @@ int AndroidNewAI::GetAttackTimes()
return ai_meta->i->attack_times(); return ai_meta->i->attack_times();
} }
} }

View File

@ -3,62 +3,16 @@
#include "aicomponent.h" #include "aicomponent.h"
#include "weakptr.h" #include "weakptr.h"
enum AndroidState_e enum AndroidStateEx_e : int;
{ enum AndroidState_e : int;
AS_thinking, struct OldAiData;
AS_moving, struct AINode;
AS_attack
};
enum AndroidStateEx_e
{
ASE_Idle = 0,
ASE_Thinking = 1,
ASE_Attack = 2,
ASE_RandomWalk = 3,
ASE_Pursuit = 4
};
class Human;
class AINode
{
public:
AndroidStateEx_e main_state = ASE_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;
CreatureWeakPtr target;
CreatureWeakPtr nearest_human;
long long last_check_nearest_human_frameno = 0;
a8::Vec2 shot_dir;
};
struct OldAiData
{
AndroidState_e state = AS_thinking;
int state_elapsed_time = 0;
CreatureWeakPtr last_target;
long long last_attack_frameno = 0;
long long last_findenemy_frameno = 0;
long long series_attack_frames = 0;
};
namespace MetaData
{
class AI;
}
class Human; class Human;
class AndroidNewAI : public AIComponent class AndroidNewAI : public AIComponent
{ {
public: public:
AndroidNewAI();
virtual ~AndroidNewAI() override; virtual ~AndroidNewAI() override;
virtual void Update(int delta_time) override; virtual void Update(int delta_time) override;
float GetAttackRate(); float GetAttackRate();
@ -84,9 +38,9 @@ private:
int GetAttackTimes(); int GetAttackTimes();
private: private:
OldAiData old_ai_data_; OldAiData* old_ai_data_ = nullptr;
MetaData::AI* ai_meta = nullptr; MetaData::AI* ai_meta = nullptr;
AINode node_; AINode* node_ = nullptr;
bool moving_ = false; bool moving_ = false;
}; };

View File

@ -15,8 +15,44 @@ enum ShotType_e
kShotHold = 2, kShotHold = 2,
}; };
enum HeroState_e : int
{
HSE_Idle = 0,
HSE_Thinking = 1,
HSE_Attack = 2,
HSE_RandomWalk = 3,
HSE_Pursuit = 4,
HSE_FollowMaster = 5
};
class HeroAINode
{
public:
HeroState_e main_state = HSE_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;
CreatureWeakPtr target;
CreatureWeakPtr nearest_human;
long long last_check_nearest_human_frameno = 0;
a8::Vec2 shot_dir;
a8::Vec2 target_pos;
};
HeroAI::HeroAI()
{
node_ = new HeroAINode();
}
HeroAI::~HeroAI() HeroAI::~HeroAI()
{ {
A8_SAFE_DELETE(node_);
} }
void HeroAI::Update(int delta_time) void HeroAI::Update(int delta_time)
@ -52,9 +88,9 @@ void HeroAI::UpdateAI()
abort(); abort();
} }
} }
++node_.exec_frame_num; ++node_->exec_frame_num;
hero->shot_hold = false; hero->shot_hold = false;
switch (node_.main_state) { switch (node_->main_state) {
case HSE_Idle: case HSE_Idle:
{ {
UpdateIdle(); UpdateIdle();
@ -99,7 +135,7 @@ void HeroAI::UpdateAI()
void HeroAI::UpdateIdle() void HeroAI::UpdateIdle()
{ {
Hero* hero = (Hero*)owner; Hero* hero = (Hero*)owner;
if (hero->room->GetFrameNo() > node_.frameno + node_.param1) { if (hero->room->GetFrameNo() > node_->frameno + node_->param1) {
ChangeToStateAI(HSE_Thinking); ChangeToStateAI(HSE_Thinking);
} }
} }
@ -125,10 +161,10 @@ void HeroAI::UpdateThinking()
} }
Creature* target = GetTarget(); Creature* target = GetTarget();
if (target) { if (target) {
node_.target.Attach(target); node_->target.Attach(target);
ChangeToStateAI(HSE_Attack); ChangeToStateAI(HSE_Attack);
} else { } else {
if (hero->room->GetFrameNo() >= node_.next_random_move_frameno) { if (hero->room->GetFrameNo() >= node_->next_random_move_frameno) {
if ((rand() % 7) < 4) { if ((rand() % 7) < 4) {
ChangeToStateAI(HSE_Idle); ChangeToStateAI(HSE_Idle);
} else { } else {
@ -136,7 +172,7 @@ void HeroAI::UpdateThinking()
} }
} else { } else {
ChangeToStateAI(HSE_Idle); ChangeToStateAI(HSE_Idle);
node_.param1 = node_.next_random_move_frameno - hero->room->GetFrameNo(); node_->param1 = node_->next_random_move_frameno - hero->room->GetFrameNo();
} }
} }
} }
@ -145,18 +181,18 @@ void HeroAI::UpdateThinking()
void HeroAI::UpdateAttack() void HeroAI::UpdateAttack()
{ {
Hero* myself = (Hero*)owner; Hero* myself = (Hero*)owner;
if (!node_.target.Get() || node_.target.Get()->dead) { if (!node_->target.Get() || node_->target.Get()->dead) {
ChangeToStateAI(HSE_Thinking); ChangeToStateAI(HSE_Thinking);
return; return;
} }
if (node_.exec_frame_num > SERVER_FRAME_RATE * 8) { if (node_->exec_frame_num > SERVER_FRAME_RATE * 8) {
ChangeToStateAI(HSE_Thinking); ChangeToStateAI(HSE_Thinking);
return; return;
} }
if (myself->HasBuffEffect(kBET_Vertigo)) { if (myself->HasBuffEffect(kBET_Vertigo)) {
return; return;
} }
float distance = myself->GetPos().Distance(node_.target.Get()->GetPos()); float distance = myself->GetPos().Distance(node_->target.Get()->GetPos());
if (distance > GetAttackRange()) { if (distance > GetAttackRange()) {
if (ai_meta->i->pursuit_radius() <= 0) { if (ai_meta->i->pursuit_radius() <= 0) {
//站桩 //站桩
@ -176,12 +212,12 @@ void HeroAI::UpdateAttack()
case kShotClick: case kShotClick:
{ {
if (ai_meta->i->attack_interval() > 0) { if (ai_meta->i->attack_interval() > 0) {
if (node_.shot_times < GetAttackTimes()) { if (node_->shot_times < GetAttackTimes()) {
DoShotAI(); DoShotAI();
} else { } else {
ChangeToStateAI(HSE_Idle); ChangeToStateAI(HSE_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 = ai_meta->i->attack_interval() / 1000 * SERVER_FRAME_RATE;
} }
} else { } else {
myself->shot_hold = true; myself->shot_hold = true;
@ -206,7 +242,7 @@ void HeroAI::UpdateAttack()
void HeroAI::UpdateRandomWalk() void HeroAI::UpdateRandomWalk()
{ {
Hero* hero = (Hero*)owner; Hero* hero = (Hero*)owner;
if (hero->room->GetFrameNo() > node_.frameno + node_.param1) { if (hero->room->GetFrameNo() > node_->frameno + node_->param1) {
ChangeToStateAI(HSE_Thinking); ChangeToStateAI(HSE_Thinking);
} }
} }
@ -214,12 +250,12 @@ void HeroAI::UpdateRandomWalk()
void HeroAI::UpdatePursuit() void HeroAI::UpdatePursuit()
{ {
Hero* myself = (Hero*)owner; Hero* myself = (Hero*)owner;
float distance = myself->GetPos().Distance(node_.target.Get()->GetPos()); float distance = myself->GetPos().Distance(node_->target.Get()->GetPos());
if (!myself->HasBuffEffect(kBET_Jump) && if (!myself->HasBuffEffect(kBET_Jump) &&
distance < GetAttackRange()) { distance < GetAttackRange()) {
ChangeToStateAI(HSE_Attack); ChangeToStateAI(HSE_Attack);
} else { } else {
if (node_.exec_frame_num > 100 * 2) { if (node_->exec_frame_num > 100 * 2) {
ChangeToStateAI(HSE_RandomWalk); ChangeToStateAI(HSE_RandomWalk);
} }
} }
@ -229,7 +265,7 @@ void HeroAI::UpdateFollowMaster()
{ {
Hero* myself = (Hero*)owner; Hero* myself = (Hero*)owner;
if (myself->master.Get()) { if (myself->master.Get()) {
float mdistance = myself->GetPos().ManhattanDistance(node_.target_pos); float mdistance = myself->GetPos().ManhattanDistance(node_->target_pos);
if (mdistance < 10) { if (mdistance < 10) {
ChangeToStateAI(HSE_Thinking); ChangeToStateAI(HSE_Thinking);
} }
@ -247,7 +283,7 @@ void HeroAI::DoMoveAI()
auto old_on_move_collision_func = hero->on_move_collision; auto old_on_move_collision_func = hero->on_move_collision;
hero->on_move_collision = hero->on_move_collision =
[this] () { [this] () {
if (node_.main_state == HSE_FollowMaster) { if (node_->main_state == HSE_FollowMaster) {
ChangeToStateAI(HSE_FollowMaster); ChangeToStateAI(HSE_FollowMaster);
} else { } else {
ChangeToStateAI(HSE_RandomWalk); ChangeToStateAI(HSE_RandomWalk);
@ -266,57 +302,57 @@ void HeroAI::ChangeToStateAI(HeroState_e to_state)
switch (to_state) { switch (to_state) {
case HSE_Idle: case HSE_Idle:
{ {
node_.target.Reset(); node_->target.Reset();
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; moving_ = false;
if (hero->room->GetGasData().gas_mode == GasInactive || if (hero->room->GetGasData().gas_mode == GasInactive ||
hero->room->IsWaitingStart() || hero->room->IsWaitingStart() ||
hero->HasBuffEffect(kBET_Jump)) { hero->HasBuffEffect(kBET_Jump)) {
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 HSE_Thinking: case HSE_Thinking:
{ {
node_.target.Reset(); node_->target.Reset();
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; moving_ = false;
} }
break; break;
case HSE_Attack: case HSE_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; moving_ = false;
node_.shot_times = 0; node_->shot_times = 0;
} }
break; break;
case HSE_RandomWalk: case HSE_RandomWalk:
{ {
moving_ = true; moving_ = true;
node_.target.Reset(); node_->target.Reset();
#if 1 #if 1
node_.param1 = SERVER_FRAME_RATE * ai_meta->GetMoveTime(); node_->param1 = SERVER_FRAME_RATE * 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 = hero->room->GetFrameNo() + node_->next_random_move_frameno = hero->room->GetFrameNo() +
SERVER_FRAME_RATE * ai_meta->GetMoveIdleTime(); SERVER_FRAME_RATE * ai_meta->GetMoveIdleTime();
a8::Vec2 move_dir = a8::Vec2(1.0f, 0); a8::Vec2 move_dir = a8::Vec2(1.0f, 0);
move_dir.Rotate(a8::RandAngle()); move_dir.Rotate(a8::RandAngle());
move_dir.Normalize(); move_dir.Normalize();
hero->SetMoveDir(move_dir); hero->SetMoveDir(move_dir);
hero->SetAttackDir(hero->GetMoveDir()); hero->SetAttackDir(hero->GetMoveDir());
if (node_.param1 <= 1) { if (node_->param1 <= 1) {
moving_ = false; moving_ = false;
} }
} }
@ -324,8 +360,8 @@ void HeroAI::ChangeToStateAI(HeroState_e to_state)
case HSE_Pursuit: case HSE_Pursuit:
{ {
moving_ = true; moving_ = true;
if (node_.target.Get()) { if (node_->target.Get()) {
a8::Vec2 move_dir = node_.target.Get()->GetPos() - hero->GetPos(); a8::Vec2 move_dir = node_->target.Get()->GetPos() - hero->GetPos();
move_dir.Normalize(); move_dir.Normalize();
hero->SetMoveDir(move_dir); hero->SetMoveDir(move_dir);
hero->SetAttackDir(hero->GetMoveDir()); hero->SetAttackDir(hero->GetMoveDir());
@ -344,14 +380,14 @@ void HeroAI::ChangeToStateAI(HeroState_e to_state)
move_dir.Normalize(); move_dir.Normalize();
hero->SetMoveDir(move_dir); hero->SetMoveDir(move_dir);
hero->SetAttackDir(hero->GetMoveDir()); hero->SetAttackDir(hero->GetMoveDir());
node_.target_pos = target_pos; node_->target_pos = target_pos;
} }
} }
break; break;
} }
node_.main_state = to_state; node_->main_state = to_state;
node_.frameno = hero->room->GetFrameNo(); node_->frameno = hero->room->GetFrameNo();
node_.exec_frame_num = 0; node_->exec_frame_num = 0;
} }
Creature* HeroAI::GetTarget() Creature* HeroAI::GetTarget()
@ -379,8 +415,8 @@ Creature* HeroAI::GetTarget()
} }
}); });
if (target) { if (target) {
node_.nearest_human.Attach(target); node_->nearest_human.Attach(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;
@ -403,15 +439,15 @@ float HeroAI::GetAttackRange()
void HeroAI::DoShotAI() void HeroAI::DoShotAI()
{ {
Hero* myself = (Hero*)owner; Hero* myself = (Hero*)owner;
if (!node_.target.Get()) { if (!node_->target.Get()) {
return; return;
} }
bool shot_ok = false; bool shot_ok = false;
a8::Vec2 shot_dir = myself->GetAttackDir(); a8::Vec2 shot_dir = myself->GetAttackDir();
if (node_.total_shot_times >= node_.next_total_shot_times) { if (node_->total_shot_times >= node_->next_total_shot_times) {
shot_dir = node_.target.Get()->GetPos() - myself->GetPos(); shot_dir = node_->target.Get()->GetPos() - myself->GetPos();
node_.next_total_shot_times += 7 + (rand() % 6); node_->next_total_shot_times += 7 + (rand() % 6);
myself->SetAttackDir(shot_dir); myself->SetAttackDir(shot_dir);
} }
if (std::abs(shot_dir.x) > FLT_EPSILON || if (std::abs(shot_dir.x) > FLT_EPSILON ||
@ -431,11 +467,11 @@ void HeroAI::DoShotAI()
myself->Shot(shot_dir, shot_ok, DEFAULT_FLY_DISTANCE); myself->Shot(shot_dir, shot_ok, DEFAULT_FLY_DISTANCE);
myself->SetAttackDir(old_attack_dir); myself->SetAttackDir(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;
} }
} }
} }

View File

@ -3,46 +3,13 @@
#include "aicomponent.h" #include "aicomponent.h"
#include "weakptr.h" #include "weakptr.h"
namespace MetaData enum HeroState_e : int;
{ class HeroAINode;
class AI;
}
enum HeroState_e
{
HSE_Idle = 0,
HSE_Thinking = 1,
HSE_Attack = 2,
HSE_RandomWalk = 3,
HSE_Pursuit = 4,
HSE_FollowMaster = 5
};
class Human;
class HeroAINode
{
public:
HeroState_e main_state = HSE_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;
CreatureWeakPtr target;
CreatureWeakPtr nearest_human;
long long last_check_nearest_human_frameno = 0;
a8::Vec2 shot_dir;
a8::Vec2 target_pos;
};
class HeroAI : public AIComponent class HeroAI : public AIComponent
{ {
public: public:
HeroAI();
virtual ~HeroAI() override; virtual ~HeroAI() override;
virtual void Update(int delta_time) override; virtual void Update(int delta_time) override;
float GetAttackRate(); float GetAttackRate();
@ -65,6 +32,6 @@ private:
private: private:
MetaData::AI* ai_meta = nullptr; MetaData::AI* ai_meta = nullptr;
HeroAINode node_; HeroAINode* node_ = nullptr;
bool moving_ = false; bool moving_ = false;
}; };

View File

@ -19,6 +19,15 @@ enum ShotType_e
kShotHold = 2, kShotHold = 2,
}; };
enum ZombieState_e : int
{
ZSE_Idle = 0,
ZSE_Thinking = 1,
ZSE_Attack = 2,
ZSE_RandomWalk = 3,
ZSE_Pursuit = 4
};
class ZombieAINode class ZombieAINode
{ {
public: public:

View File

@ -2,16 +2,7 @@
#include "aicomponent.h" #include "aicomponent.h"
enum ZombieState_e enum ZombieState_e : int;
{
ZSE_Idle = 0,
ZSE_Thinking = 1,
ZSE_Attack = 2,
ZSE_RandomWalk = 3,
ZSE_Pursuit = 4
};
class Human;
class Creature; class Creature;
class ZombieAINode; class ZombieAINode;
class ZombieModeAI : public AIComponent class ZombieModeAI : public AIComponent