Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <ctime>
- #include <math.h>
- #include <grx20.h>
- #include <grxkeys.h>
- const int _minSpeed = 100; // минимальная скорость фигуры
- const int _maxSpeed = 500;
- const int _maxNumber = 500; // максимальное количество фигур (без учета главной)
- const float pi = 3.1415;
- const float pi2 = 6.283;
- int _masterX = GrMaxX()/2; // положение главной фигуры
- int _masterY = GrMaxY()/2;
- int _number = 0; // текущее количество фигур
- class myDot {
- public:
- myDot(bool master = false);
- int getX(); // получить координаты
- int getY();
- void move(); // функция для обработки перемещения фигуры
- void draw(); // отрисовка текущего положения
- void hide(); // закрашивание текущего положения цветом фона
- void hideOld(); // то же самое , только для предыдущего положения
- void redraw(); // перерисовка фигуры (удаление старой и отрисовка новой позиции)
- void MaD(); // перерисовка фигуры с перемещением
- protected:
- virtual void privateDraw(int x, int y, int colVal); // функция для отрисовки фигуры
- virtual bool borderCollisionCheckX(int x); // проверка колизии фигуры с границей
- virtual bool borderCollisionCheckY(int y);
- void update(); // обновление таймера (для сохранения скорости при понижении частоты отрисовка) + обновление направления зависимых фигур
- unsigned int prevTime; // предыдущее время обновления
- float speedMult; // множитель скорости (для калибровки скорости)
- void masterPositionUpdate(); // обновление положения главной фигуры
- bool slave; // подчиненная фигура или главная
- bool hided; // скрыта или видима
- int distToMaster; // расстояние до главной фигуры
- int masterOffense; // расстояние , на которое отстает зависимая фигура от главной
- float masterAngleOffense; // погрешность направления (для неравномерного распределения зависимых фигур)
- int x;
- int y;
- int xSpeed(); // функции для расчета скорости
- int ySpeed();
- int xOld; // координаты для перерисовки фигуры
- int yOld;
- float velAngle; // направление скорости (в радианах)
- int velocity; // скорость (в пискелях в секунду)
- int color;
- };
- class myBox : public myDot {
- public:
- myBox(bool main=false);
- protected:
- void privateDraw(int xVal, int yVal, int colVal);
- bool borderCollisionCheckX(int xVal);
- bool borderCollisionCheckY(int yVal);
- int halfSizeX; //половина размера квадрата (для удобства расчета положения относительно середины фигуры)
- int halfSizeY;
- };
- class myCircle : public myDot {
- public:
- myCircle(bool main=false);
- protected:
- void privateDraw(int xVal, int yVal, int colVal);
- bool borderCollisionCheckX(int xVal);
- bool borderCollisionCheckY(int yVal);
- int radius;
- };
- int main()
- {
- srand(time(0));
- GrSetMode(GR_width_height_graphics, 640, 480);
- GrFilledBox(0, 0, GrMaxX(), GrMaxY(), 0); //установка цвета фона
- myDot *mainFigure; // указатель на главную фигуру
- mainFigure = new myCircle(true);
- myDot *(dots[_maxNumber]); // массив подчиненных фигур
- for (int i = 0; i < _maxNumber; i++) // случайный выбор типа фигуры
- switch (rand()%3) {
- case 0: dots[i] = new myDot;
- break;
- case 1: dots[i] = new myCircle;
- break;
- case 2: dots[i] = new myBox;
- break;
- }
- GrKeyType key = GrKey_0;
- while (key != GrKey_Escape) { // отрисовка и расчет фигур до нажатия Esc
- if (GrKeyPressed()) { // получение нажатой клавиши
- key = GrKeyRead();
- switch (key) {
- case GrKey_F1: if (_number < _maxNumber) _number++; // если нажата F1, то +1 фигура
- break;
- case GrKey_F2: if (_number > 0) {dots[_number-1] -> hide(); _number--; }; // если нажата F2, то удаление 1 фигуры
- break;
- };
- };
- mainFigure -> move(); // перемещение и затирание старой позиции главной фигуры
- //mainFigure -> hideOld();
- for (int i = 0; i < _number; i++) { // то же самое для подчиненных
- dots[i]->move();
- //dots[i]->hideOld();
- };
- GrFilledBox(0, 0, GrMaxX(), GrMaxY(), 0);
- mainFigure -> draw(); // отрисовка главной фигуры и подчиненных
- for (int i = 0; i < _number; i++) dots[i]->draw();
- GrSleep(20); // пропуск нескольких милисекунд для уменьшения количества морганий
- };
- return 0;
- }
- myDot::myDot(bool master) { // конструктор точки
- x = (rand() % (GrMaxX() / 2)) + GrMaxX() / 4; //случайное положение от четверти и до 3/4 экрана
- y = (rand() % (GrMaxY() / 2)) + GrMaxY() / 4;
- xOld = x;
- yOld = y;
- slave = !master;
- hided = true;
- distToMaster = 0;
- masterOffense = (rand() % 40) + 5;
- masterAngleOffense = ((float)(rand() % 40)-20)/180*pi; // выбор погрешности в диапазоне +-20* в радианах
- velAngle = !slave ? ((float)(rand() % 360) / 180 * pi) : 0;
- velocity = rand() % (_maxSpeed - _minSpeed) + _minSpeed; // выбор скорости в диапазоне
- int tran = rand()%14+1;
- color = slave? (tran > 9 ? tran+1:tran ): 10; // подчиненные разных цветов, главный - зеленого
- prevTime = 0;
- speedMult = 0;
- };
- int myDot::getX() { return x; };
- int myDot::getY() { return y; };
- void myDot::move() {
- update();
- int newX = x + xSpeed(); // получение новых значений
- int newY = y + ySpeed();
- if (!slave) { // Если не подчиненный, то обработка колизии и направления
- if (borderCollisionCheckX(newX)) {
- xOld = x;
- x = newX;
- }
- else {
- xOld = x;
- velAngle = (velAngle > pi) ? (pi2 + pi - velAngle) : (pi - velAngle); // при столкновении со стеной меняем угол на противоположный относительно оси синусов
- };
- if (borderCollisionCheckY(newY)) {
- yOld = y;
- y = newY;
- }
- else {
- yOld = y;
- velAngle = pi2 - velAngle; // при столкновении с полом или потолком меняем угол на противоположный относительно оси косинусов
- };
- masterPositionUpdate(); // обновление позиции косинусов
- }
- else { // если подчиненный, то просто перемещаем точку
- xOld = x;
- x = newX;
- yOld = y;
- y = newY;
- }
- };
- int myDot::xSpeed() {
- if (slave) // если подчиненный
- return round(cos(velAngle) * velocity * speedMult * (distToMaster - masterOffense) / 150); // перемножение синуса и скорости (горизонтальная скорость) на временной коэффициент и расстояние до мастера
- else // для главной фигуры то же самое, только без расстояния
- return round(cos(velAngle) * velocity * speedMult);
- };
- int myDot::ySpeed() { // то же самое, только с синусом
- if (slave)
- return round(sin(velAngle) * velocity * speedMult * (distToMaster - masterOffense) / 150);
- else
- return round(sin(velAngle) * velocity * speedMult);
- };
- void myDot::draw() { privateDraw(x, y, color); }; // оболочки для функций (для удобства)
- void myDot::hide() { privateDraw(x, y, 0); hided = true;}; // при скрытии дополнительно поднимается флаг "скрыт"
- void myDot::hideOld() { privateDraw(xOld, yOld, 0); };
- void myDot::redraw() { hideOld(); draw(); };
- void myDot::MaD() { move(); redraw(); };
- void myDot::privateDraw(int x, int y, int colVal) {
- GrFilledCircle(x, y, 3, colVal);
- };
- bool myDot::borderCollisionCheckX(int x) {
- return (x + 3 < GrMaxX() && x > 3);
- };
- bool myDot::borderCollisionCheckY(int y) {
- return (y + 3 < GrMaxY() && y > 3);
- };
- void myDot::update() {
- //timer update
- unsigned int time = clock();
- if (!hided)
- speedMult = (float)(time - prevTime) / 1000; // временной коэф. - это разница текущего и предыдущего времени вызова функции перемещения в секундах
- else { // если фигура скрыта, то временной коэффициент обнуляется (иначе из-за большого времени простоя фигура вылетает за границы)
- speedMult = 0;
- hided = false;
- };
- prevTime = time;
- // position update
- if (slave) { // если подчиненный, то дополнительно определяется направление до главной фигуры (с погрешностью) с помощью арктангенса
- int offX = _masterX - x;
- int offY = _masterY - y;
- distToMaster = round(sqrt(offX * offX + offY * offY));
- velAngle = atan2((float)offY / distToMaster, (float)offX / distToMaster) + masterAngleOffense;
- }
- };
- void myDot::masterPositionUpdate(){
- _masterX = x;
- _masterY = y;
- };
- myBox::myBox(bool main): myDot(main){ // переопределения функций для прямоугольника
- halfSizeX = rand()%10+10;
- halfSizeY = rand()%10+10;
- };
- void myBox::privateDraw(int x, int y, int colVal) {
- GrFilledBox(x-halfSizeX, y-halfSizeY, x+halfSizeX,y+halfSizeY, colVal);
- }
- bool myBox::borderCollisionCheckX(int x) {
- return (x + halfSizeX < GrMaxX() && x > halfSizeX);
- };
- bool myBox::borderCollisionCheckY(int y) {
- return (y + halfSizeY < GrMaxY() && y > halfSizeY);
- };
- myCircle::myCircle(bool main): myDot(main) { // для окружности
- radius = rand()%10+10;
- };
- void myCircle::privateDraw(int x, int y, int colVal) {
- GrFilledCircle(x, y, radius, colVal);
- }
- bool myCircle::borderCollisionCheckX(int x) {
- return (x + radius < GrMaxX() && x > radius);
- };
- bool myCircle::borderCollisionCheckY(int y) {
- return (y +radius < GrMaxY() && y > radius);
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement