Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

physics #90

Merged
merged 6 commits into from
Apr 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions agario/local_runner/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const double VIS_SHIFT = 10.0; // dx = qCos(angle) * VS; dy = qSin(angle) * VS
const double DRAW_SPEED_FACTOR = 14.0;
//const double INERTION_FACTOR = 10.0;

const double COLLISION_POWER = 20.;
//const double SPEED_FACTOR = 25.0; // speed = SF / sqrt(mass)
//const double RADIUS_FACTOR = 2.0; // radius = RF * sqrt(mass)
const double MASS_EAT_FACTOR = 1.20; // mass > food.mass * MEF
Expand Down
73 changes: 49 additions & 24 deletions agario/local_runner/entities/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,36 +293,61 @@ class Player : public Circle
return new_player;
}

double tangent_projection(Player *c1, Player *c2, double dist) {
if (dist > 0 && c1->speed > 0) {
double speed_x = c1->speed * qCos(c1->angle);
double speed_y = c1->speed * qSin(c1->angle);

double norm_x = -(c1->y - c2->y), norm_y = c1->x - c2->x;
double scalar = norm_x * speed_x + norm_y * speed_y;
double cos_beta = scalar / dist / c1->speed;
return qAcos(cos_beta);
}
return 0.0;
}

bool can_fuse(Player *frag) {
double dist = frag->calc_dist(x, y);
double nR = radius + frag->getR();

if (frag->fuse_timer > 0 && dist <= nR && !is_fast) {
double beta = tangent_projection(this, frag, dist);
if (qAbs(beta) < M_PI / 2) {
angle -= beta;
}
// speed *= qCos(beta);
return fuse_timer == 0 && frag->fuse_timer == 0 && dist <= nR;
}

void collisionCalc(Player *other) {
if (is_fast || other->is_fast) { // do not collide splits
return;
}
if (frag->getM() < mass) {
if (frag->fuse_timer == 0 && dist <= nR) {
return true;
}
double dist = this->calc_dist(other->x, other->y);
if (dist >= radius + other->radius) {
Copy link
Contributor

@adler3d adler3d Apr 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

с точки зрения производительности выгодно сравнивать квадраты расстояний, т.к вычисления корня вроде где-то в 4 раз медленнее умножения.

то есть вот так будет чуть быстрее:

double sqr_dist = this->calc_qdist(other->x, other->y);
if (sqr_dist >= sqr(radius + other->radius)) return;
...

PS: я не знаю есть ли в qt функция sqr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

то, что квадрат быстрее корня - мне пруфа не надо

Но если коллизия таки есть, то корень используется ниже в формуле. Для симуляции в стратегии это может и критично, в раннере это микро/наносекунды. Да и в стратегии я бы сначала посмотрел на профайлер до такой оптимизации

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В принципе если суть формулы вычисления силы коллизии оставить такой, как есть - ниже тоже можно воспользоваться квадратами и убрать ещё одно умножение, кажется

Copy link
Contributor

@adler3d adler3d Apr 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Но если коллизия таки есть, то корень используется ниже в формуле

Там же O(n*n) алгоритм поиска столкновений, то есть в 99% случаев выполняется ветка где нет коллизии, поэтому она должна работать быстро.
Можно вообще только по координате X сравнить и выйти, выгоды будет больше чем от избавления от корня.

Для симуляции в стратегии это может и критично, в раннере это микро/наносекунды.

Согласен. Особенно учитывая что фрагментов редко когда больше 10.

Copy link
Contributor Author

@DragoonXen DragoonXen Apr 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Судя по тому, что я видел, то там коллизии будут куда чаще, чем в 1% случаев.

Да, можно ускорить, я не спорю. Нужно ли

Я просто не хотел усложнять для понимания код. Кому нужно - сделают)

Copy link
Contributor

@adler3d adler3d Apr 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

26x
ого, реально 73% а не 99% как я думал.

return;
}

// vector from centers
double collisionVectorX = this->x - other->x;
double collisionVectorY = this->y - other->y;
// normalize to 1
double vectorLen = qSqrt(collisionVectorX * collisionVectorX + collisionVectorY * collisionVectorY);
if (vectorLen < 1e-9) { // collision object in same point??
return;
}
collisionVectorX /= vectorLen;
collisionVectorY /= vectorLen;

double collisionForce = 1. - dist / (radius + other->radius);
collisionForce *= collisionForce;
collisionForce *= COLLISION_POWER;

double sumMass = getM() + other->getM();
// calc influence on us
{
double currPart = other->getM() / sumMass; // more influence on us if other bigger and vice versa

double dx = speed * qCos(angle);
double dy = speed * qSin(angle);
dx += collisionForce * currPart * collisionVectorX;
dy += collisionForce * currPart * collisionVectorY;
this->speed = qSqrt(dx * dx + dy * dy);
this->angle = qAtan2(dy, dx);
}

// calc influence on other
{
double otherPart = getM() / sumMass;

double dx = other->speed * qCos(other->angle);
double dy = other->speed * qSin(other->angle);
dx -= collisionForce * otherPart * collisionVectorX;
dy -= collisionForce * otherPart * collisionVectorY;
other->speed = qSqrt(dx * dx + dy * dy);
other->angle = qAtan2(dy, dx);
}
return false;
}

void fusion(Player *frag) {
Expand Down
19 changes: 19 additions & 0 deletions agario/local_runner/mechanic.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,9 @@ class Mechanic : public QObject

void who_need_fusion() {
for (Player *player : player_array) {
if (player->logical == Player::FUSED) {
continue;
}
PlayerArray fragments = get_players_by_id(player->getId());
if (fragments.length() == 1) {

Expand Down Expand Up @@ -589,6 +592,22 @@ class Mechanic : public QObject
}
}
}

QSet<int> playerIds;
for (Player *player : player_array) {
playerIds.insert(player->getId());
}

for (auto sId : playerIds) {
PlayerArray fragments = get_players_by_id(sId);
for (int i = 0; i != fragments.size(); ++i) {
Player *curr = fragments[i];
for (int j = i + 1; j < fragments.size(); ++j) {
curr->collisionCalc(fragments[j]);
}
}
}

for (Player *player : player_array) {
bool changed = player->move(ins.GAME_WIDTH, ins.GAME_HEIGHT);
if (changed) {
Expand Down