-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPhysics.cpp
More file actions
123 lines (105 loc) · 5.51 KB
/
Copy pathPhysics.cpp
File metadata and controls
123 lines (105 loc) · 5.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "Physics.h"
#include <cmath>
#include <algorithm>
// Ìåòîä îáðàáîòêè âñåõ ñòîëêíîâåíèé â èãðå
void Physics::HandleCollisions(Table& table, std::vector<Ball*>& balls) {
// Îáðàáîòêà ñòîëêíîâåíèé ìåæäó øàðàìè
for (size_t i = 0; i < balls.size(); ++i) {
for (size_t j = i + 1; j < balls.size(); ++j) {
if (DetectCollision(balls[i], balls[j])) {
DynamicCollision(balls[i], balls[j]);
}
}
}
// Îáðàáîòêà ñòîëêíîâåíèé ìåæäó øàðàìè è ñòåíàìè ñòîëà
for (auto& ball : balls) {
for (auto& wall : table.getWalls()) {
Vector2D* collisionPoint = DetectCollisionEdge(ball, &wall);
if (collisionPoint) {
delete collisionPoint;
}
}
}
// Îáðàáîòêà ñòîëêíîâåíèé ìåæäó øàðàìè è ëóçàìè
for (auto& ball : balls) {
for (auto& pocket : table.getPockets()) {
if (DetectCollisionHole(ball, &pocket)) {
ball->isPocketed = true; // Øàð çàáèò â ëóçó
ball->velocity.setX(0); // Îñòàíîâêà øàðà
ball->velocity.setY(0); // Îñòàíîâêà øàðà
}
}
}
}
// Ìåòîä îáíàðóæåíèÿ ñòîëêíîâåíèÿ äâóõ øàðîâ
bool Physics::DetectCollision(Ball* ball1, Ball* ball2) {
// Âû÷èñëåíèå ðàññòîÿíèÿ ìåæäó öåíòðàìè øàðîâ
float distanceX = ball1->position.getX() - ball2->position.getX();
float distanceY = ball1->position.getY() - ball2->position.getY();
float distance = std::sqrt(distanceX * distanceX + distanceY * distanceY);
float overlap = 0.5f * (distance - ball1->radius - ball2->radius);
// Åñëè ðàññòîÿíèå ìåíüøå ñóììû ðàäèóñîâ, çíà÷èò øàðû ñòàëêèâàþòñÿ
if (distance < ball1->radius + ball2->radius) {
// Êîððåêòèðîâêà ïîçèöèé øàðîâ äëÿ óñòðàíåíèÿ íàëîæåíèÿ
ball1->position.setX(ball1->position.getX() - overlap * (distanceX / distance));
ball1->position.setY(ball1->position.getY() - overlap * (distanceY / distance));
ball2->position.setX(ball2->position.getX() + overlap * (distanceX / distance));
ball2->position.setY(ball2->position.getY() + overlap * (distanceY / distance));
return true;
}
return false;
}
// Ìåòîä îáðàáîòêè äèíàìè÷åñêîãî ñòîëêíîâåíèÿ äâóõ øàðîâ
void Physics::DynamicCollision(Ball* ball1, Ball* ball2) {
// Âû÷èñëåíèå ðàññòîÿíèÿ ìåæäó öåíòðàìè øàðîâ
float distanceX = ball1->position.getX() - ball2->position.getX();
float distanceY = ball1->position.getY() - ball2->position.getY();
float distance = std::sqrt(distanceX * distanceX + distanceY * distanceY);
// Íîðìàëèçàöèÿ íàïðàâëåíèÿ ñòîëêíîâåíèÿ
float normalX = (ball2->position.getX() - ball1->position.getX()) / distance;
float normalY = (ball2->position.getY() - ball1->position.getY()) / distance;
float relativeVelocityX = ball1->velocity.getX() - ball2->velocity.getX();
float relativeVelocityY = ball1->velocity.getY() - ball2->velocity.getY();
float impactSpeed = 2.0 * (normalX * relativeVelocityX + normalY * relativeVelocityY) / (ball1->mass + ball2->mass);
// Îáíîâëåíèå ñêîðîñòåé øàðîâ ïîñëå ñòîëêíîâåíèÿ
ball1->velocity.setX(ball1->velocity.getX() - impactSpeed * ball2->mass * normalX);
ball1->velocity.setY(ball1->velocity.getY() - impactSpeed * ball2->mass * normalY);
ball2->velocity.setX(ball2->velocity.getX() + impactSpeed * ball1->mass * normalX);
ball2->velocity.setY(ball2->velocity.getY() + impactSpeed * ball1->mass * normalY);
}
// Ìåòîä îáíàðóæåíèÿ ñòîëêíîâåíèÿ øàðà ñ ëóçîé
bool Physics::DetectCollisionHole(Ball* ball, Pocket* pocket) {
float distanceX = ball->position.getX() - pocket->getPosition().getX();
float distanceY = ball->position.getY() - pocket->getPosition().getY();
float distance = std::sqrt(distanceX * distanceX + distanceY * distanceY);
// Ïðîâåðêà, íàõîäèòñÿ ëè øàð â ïðåäåëàõ ðàäèóñà ëóçû
return distance < ball->radius + pocket->getRadius();
}
// Ìåòîä îáíàðóæåíèÿ ñòîëêíîâåíèÿ øàðà ñ êðàåì ñòîëà
Vector2D* Physics::DetectCollisionEdge(Ball* ball, Wall* wall) {
Vector2D wallStart = wall->getStart();
Vector2D wallEnd = wall->getEnd();
Vector2D ballPosition = ball->position;
Vector2D wallVector = wallEnd - wallStart;
Vector2D ballToWallStart = ballPosition - wallStart;
float wallLengthSquared = wallVector.dot(wallVector);
float projectionFactor = ballToWallStart.dot(wallVector) / wallLengthSquared;
// Îãðàíè÷åíèå ôàêòîðà ïðîåêöèè, ÷òîáû òî÷êà íàõîäèëàñü íà ñåãìåíòå ñòåíû
projectionFactor = std::max(0.0f, std::min(1.0f, projectionFactor));
// Âû÷èñëåíèå áëèæàéøåé òî÷êè íà ñòåíå
Vector2D closestPoint = wallStart + wallVector * projectionFactor;
Vector2D collisionNormal = ballPosition - closestPoint;
float collisionDistance = collisionNormal.length();
// Ïðîâåðêà, íàõîäèòñÿ ëè øàð â ïðåäåëàõ ðàäèóñà ñòåíû
if (collisionDistance < ball->radius) {
float overlap = ball->radius - collisionDistance;
collisionNormal.normalize();
ball->position = ball->position + collisionNormal * overlap;
// Îáíîâëåíèå ñêîðîñòè øàðà ïîñëå ñòîëêíîâåíèÿ ñî ñòåíîé
float velocityDotNormal = ball->velocity.dot(collisionNormal);
ball->velocity.setX(ball->velocity.getX() - collisionNormal.getX() * velocityDotNormal * 2.0f);
ball->velocity.setY(ball->velocity.getY() - collisionNormal.getY() * velocityDotNormal * 2.0f);
return new Vector2D(closestPoint);
}
return nullptr;
}