248 lines
8.6 KiB
C++
248 lines
8.6 KiB
C++
#include "precompile.h"
|
|
|
|
#include "obstacle.h"
|
|
#include "metamgr.h"
|
|
#include "room.h"
|
|
#include "collider.h"
|
|
#include "building.h"
|
|
#include "human.h"
|
|
#include "app.h"
|
|
#include "typeconvert.h"
|
|
|
|
Obstacle::Obstacle():Entity()
|
|
{
|
|
entity_type = kET_Obstacle;
|
|
++App::Instance()->perf.entity_num[kET_Obstacle];
|
|
}
|
|
|
|
Obstacle::~Obstacle()
|
|
{
|
|
--App::Instance()->perf.entity_num[kET_Obstacle];
|
|
}
|
|
|
|
void Obstacle::Initialize()
|
|
{
|
|
Entity::Initialize();
|
|
health = meta->i->hp();
|
|
RecalcSelfCollider();
|
|
}
|
|
|
|
void Obstacle::RecalcSelfCollider()
|
|
{
|
|
if (is_door) {
|
|
//门
|
|
if (!self_collider2_) {
|
|
self_collider2_ = new AabbCollider();
|
|
self_collider2_->owner = this;
|
|
AddCollider(self_collider2_);
|
|
a8::Vec2 old_pos = pos;
|
|
{
|
|
pos = a8::Vec2(building->pos.x + door_state1->x() - building->meta->i->tilewidth() / 2.0,
|
|
building->pos.y + door_state1->y() - building->meta->i->tileheight() / 2.0);
|
|
self_collider2_->_min = a8::Vec2(0.0f - door_state0->width() / 2.0f,
|
|
0.0f - door_state0->height() / 2.0f);
|
|
self_collider2_->_max = a8::Vec2(door_state0->width() / 2.0f, door_state0->height() / 2.0f);
|
|
room->map_service.AddCollider(self_collider2_);
|
|
}
|
|
{
|
|
pos = a8::Vec2(building->pos.x + door_state0->x() - building->meta->i->tilewidth() / 2.0,
|
|
building->pos.y + door_state0->y() - building->meta->i->tileheight() / 2.0);
|
|
self_collider2_->_min = a8::Vec2(0.0f - door_state1->width() / 2.0f,
|
|
0.0f - door_state1->height() / 2.0f);
|
|
self_collider2_->_max = a8::Vec2(door_state1->width() / 2.0f, door_state1->height() / 2.0f);
|
|
room->map_service.AddCollider(self_collider2_);
|
|
}
|
|
pos = old_pos;
|
|
}
|
|
if (door_state == kDoorStateClose) {
|
|
self_collider2_->_min = a8::Vec2(0.0f - door_state0->width() / 2.0f,
|
|
0.0f - door_state0->height() / 2.0f);
|
|
self_collider2_->_max = a8::Vec2(door_state0->width() / 2.0f, door_state0->height() / 2.0f);
|
|
} else {
|
|
self_collider2_->_min = a8::Vec2(0.0f - door_state1->width() / 2.0f,
|
|
0.0f - door_state1->height() / 2.0f);
|
|
self_collider2_->_max = a8::Vec2(door_state1->width() / 2.0f, door_state1->height() / 2.0f);
|
|
}
|
|
} else if (meta->i->attack_type() != 2){
|
|
switch (meta->i->type()) {
|
|
case 1:
|
|
{
|
|
if (!self_collider_) {
|
|
self_collider_ = new CircleCollider();
|
|
self_collider_->owner = this;
|
|
AddCollider(self_collider_);
|
|
}
|
|
self_collider_->pos = a8::Vec2();
|
|
self_collider_->rad = meta->i->height() / 2.0;
|
|
room->map_service.AddCollider(self_collider_);
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
if (!self_collider2_) {
|
|
self_collider2_ = new AabbCollider();
|
|
self_collider2_->owner = this;
|
|
AddCollider(self_collider2_);
|
|
}
|
|
self_collider2_->_min = a8::Vec2(meta->i->width() / -2.0f, meta->i->height() / -2.0f);
|
|
self_collider2_->_max = a8::Vec2(meta->i->width() / 2.0f, meta->i->height() / 2.0f);
|
|
room->map_service.AddCollider(self_collider2_);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Obstacle::FillMFObjectPart(cs::MFObjectPart* part_data)
|
|
{
|
|
part_data->set_object_type(kET_Obstacle);
|
|
cs::MFObstaclePart* p = part_data->mutable_union_obj_2();
|
|
p->set_obj_uniid(entity_uniid);
|
|
TypeConvert::ToPb(pos, p->mutable_pos());
|
|
p->set_scale(1.0f);
|
|
}
|
|
|
|
void Obstacle::FillMFObjectFull(cs::MFObjectFull* full_data)
|
|
{
|
|
full_data->set_object_type(kET_Obstacle);
|
|
cs::MFObstacleFull* p = full_data->mutable_union_obj_2();
|
|
p->set_obj_uniid(entity_uniid);
|
|
TypeConvert::ToPb(pos, p->mutable_pos());
|
|
p->set_scale(1.0f);
|
|
|
|
p->set_obstacle_id(meta->i->thing_id());
|
|
p->set_health(health);
|
|
p->set_dead(dead);
|
|
p->set_dead_at_thisframe(dead ? dead_frameno <= room->frameno : false);
|
|
if (master) {
|
|
p->set_master_id(master->entity_uniid);
|
|
}
|
|
|
|
p->set_is_door(is_door);
|
|
if (is_door) {
|
|
p->set_door_id(door_id);
|
|
p->set_door_open_times(door_open_times);
|
|
p->set_door_old_state((int)door_state);
|
|
p->set_door_new_state((int)door_state);
|
|
p->set_door_house_uniid(door_house_uniid);
|
|
p->set_door_house_id(building->meta->i->mapid());
|
|
if (door_state == kDoorStateClose) {
|
|
p->set_door_width(door_state0->width());
|
|
p->set_door_height(door_state0->height());
|
|
} else {
|
|
p->set_door_width(door_state1->width());
|
|
p->set_door_height(door_state1->height());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Obstacle::GetAabbBox(AabbCollider& aabb_box)
|
|
{
|
|
if (self_collider2_) {
|
|
aabb_box = *self_collider2_;
|
|
return;
|
|
}
|
|
if (self_collider_) {
|
|
aabb_box.active = true;
|
|
aabb_box.owner = this;
|
|
aabb_box._min.x = -self_collider_->rad;
|
|
aabb_box._min.y = -self_collider_->rad;
|
|
aabb_box._max.x = self_collider_->rad;
|
|
aabb_box._max.y = self_collider_->rad;
|
|
return;
|
|
}
|
|
aabb_box.active = true;
|
|
aabb_box.owner = this;
|
|
}
|
|
|
|
void Obstacle::GetCircleBox(CircleCollider& circle_box)
|
|
{
|
|
|
|
}
|
|
|
|
void Obstacle::Explosion()
|
|
{
|
|
if (explosioned) {
|
|
return;
|
|
}
|
|
CircleCollider collider;
|
|
collider.owner = this;
|
|
collider.rad = meta->i->damage_dia();
|
|
if (meta->i->damage_dia() > 0.01f &&
|
|
meta->i->damage() > 0.01f) {
|
|
std::set<Entity*> objects;
|
|
std::set<GridCell*> grid_list;
|
|
room->grid_service.GetAllCellsByXy(pos.x, pos.y, grid_list);
|
|
for (auto& grid : grid_list) {
|
|
for (Human* hum: grid->human_list) {
|
|
if (hum->TestCollision(&collider)) {
|
|
objects.insert(hum);
|
|
}
|
|
}
|
|
for (Entity* entity : grid->entity_list) {
|
|
switch (entity->entity_type) {
|
|
case kET_Obstacle:
|
|
case kET_Building:
|
|
{
|
|
if (entity != this && entity->TestCollision(&collider)) {
|
|
objects.insert(entity);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}//end for
|
|
}
|
|
a8::Vec2 bomb_pos = pos;
|
|
room->frame_event.AddExplosion(meta->i->thing_id(), bomb_pos, 0);
|
|
for (auto& target : objects) {
|
|
switch (target->entity_type) {
|
|
case kET_Player:
|
|
{
|
|
Human* hum = (Human*)target;
|
|
if (!hum->dead && hum != master) {
|
|
float dmg = meta->i->damage();
|
|
if (master) {
|
|
dmg += master->ability.atk;
|
|
}
|
|
float def = hum->ability.def;
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
hum->OnHit();
|
|
if (!hum->HasBuffEffect(kBET_Invincible)) {
|
|
hum->DecHP(finaly_dmg, kVP_Mine, "地雷", kVW_Mine);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case kET_Obstacle:
|
|
{
|
|
Obstacle* obstacle = (Obstacle*)target;
|
|
if (!obstacle->dead && obstacle->meta->i->attack_type() == 1) {
|
|
float dmg = meta->i->damage();
|
|
float def = 0;
|
|
float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K);
|
|
|
|
obstacle->health = std::max(0.0f, obstacle->health - finaly_dmg);
|
|
obstacle->dead = obstacle->health <= 0.01f;
|
|
obstacle->dead_frameno = room->frameno;
|
|
if (obstacle->dead) {
|
|
room->ScatterDrop(obstacle->pos, obstacle->meta->i->drop());
|
|
}
|
|
obstacle->BroadcastFullState();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
explosioned = true;
|
|
NotifyDelObject();
|
|
room->RemoveObjectLater(this);
|
|
}
|