require 'ruby2d'# 1. Завантаження бібліотеки Ruby 2D # 2. Надання значень сталим налаштування: $NUM_BALLS = 30 # кількість кругів одного кольору $WALL_TIME = 7 # час існування перегородки (у секундах) $MIN_SPEED = 1 # мінімально можлива швидкість (у пікселях) $MAX_SPEED = 4 # максимально можлива швидкість (у пікселях) $BALL_DIAMETR = 10 # діаметр кола (у пікселях) $SCREEN_HEIGHT = 480 # висота вікна (у пікселях) $SCREEN_WIDTH = 640 # ширина вікна (у пікселях) $WALL_WIDTH = 6 # ширина перегородки (у пікселях) # Права межа для абсциси лівого кута зображення диска $EFFECTIVE_WIDTH = $SCREEN_WIDTH - $BALL_DIAMETR # Нижня межа для ординати нижнього кута зображення диска $EFFECTIVE_HEIGHT = $SCREEN_HEIGHT - $BALL_DIAMETR # Права межа для дисків ліворуч від перегородки $EFFECTIVE_WIDTH_WALL_LEFT = $SCREEN_WIDTH/2 - $WALL_WIDTH/2 - $BALL_DIAMETR # Ліва межа для дисків праворуч від перегородки $EFFECTIVE_WIDTH_WALL_RIGHT= $SCREEN_WIDTH/2 + $WALL_WIDTH/2 # Клас Ball (м'яч) описує диск. Кожен екземпляр класу зберігає стан окремого диску class Ball # 3. Опис класу Ball @@array = Array.new # Cтатичний масив даних про всі диски. def self.all_instances # Оголошення статичного методу для повернення @@array # статичного масиву з усіма представниками класу end def initialize(x,y,vx,vy,t) # Конструктор @vx = vx @vy = vy if t == false @img = Image.new(path: 'blue.png', height: $BALL_DIAMETR, width: $BALL_DIAMETR, x: x, y: y) else @img = Image.new(path: 'rose.png', height: $BALL_DIAMETR, width: $BALL_DIAMETR, x: x, y: y) end @@array << self # Занесення створеного представника класу до статичного масиву end def move(t) # Метод зміни координат nx = @img.x + @vx # нове значення абсциси ny = @img.y + @vy # нове значення ординати if nx > $EFFECTIVE_WIDTH # Якщо зображення при новій координаті виходить за праву межу екрану nx = 2*$EFFECTIVE_WIDTH - nx # Нове розташування після відбиття @vx = -@vx # Зміна напряму складової швидкості на протилежний end if nx < 0 # Якщо зображення при новій координаті виходить за ліву межу екрану nx = -nx # Нове розташування після відбиття @vx = -@vx # Зміна напряму складової швидкості на протилежний end if ny > $EFFECTIVE_HEIGHT # Якщо зображення при новій координаті виходить за нижню межу екрану ny = 2*$EFFECTIVE_HEIGHT - ny # Нове розташування після відбиття @vy = -@vy # Зміна напряму складової швидкості на протилежний end if ny < 0 # Якщо зображення при новій координаті виходить за верхню межу екрану ny = -ny # Нове розташування після відбиття @vy = -@vy # Зміна напряму складової швидкості на протилежний end if t == true # Якщо є перешкода... # Якщо зображення перетнуло перешкоду зліва направо if (nx >= $EFFECTIVE_WIDTH_WALL_LEFT) && (@img.x < $EFFECTIVE_WIDTH_WALL_LEFT) # Вираховуємо нове положення, враховуючи відстань після відбиття nx = 2*$EFFECTIVE_WIDTH_WALL_LEFT - nx # Нове розташування після відбиття @vx = -@vx # Зміна напряму складової швидкості на протилежний end # Якщо зображення перетнуло перешкоду справа наліво if (nx <= $EFFECTIVE_WIDTH_WALL_RIGHT) && (@img.x > $EFFECTIVE_WIDTH_WALL_RIGHT) # Вираховуємо нове положення, враховуючи відстань після відбиття nx = 2*$EFFECTIVE_WIDTH_WALL_RIGHT - nx # Нове розташування після відбиття @vx = -@vx # Зміна напряму складової швидкості на протилежний end end # Змінюємо координати зображення на щойно вирахувані @img.x = nx # абсциса @img.y = ny # ордината end end # 4. Опис початкового стану моделі set height: $SCREEN_HEIGHT # Виставляємо висоту екрану set width: $SCREEN_WIDTH # Виставляємо ширину екрану # Створення зображення перегородки посередині екрану wall = Image.new(x: $SCREEN_WIDTH/2-$WALL_WIDTH/2,y:0, width: $WALL_WIDTH, height: $SCREEN_HEIGHT, path: "wall.png") for i in 1..$NUM_BALLS # Створення дисків по одному в операторі циклу # Рожевого кольору, розташований ліворуч від перешкоди, # у випадковій точці, з випадковою швидкістю Ball.new($EFFECTIVE_WIDTH_WALL_RIGHT + rand($EFFECTIVE_WIDTH_WALL_LEFT),rand($SCREEN_HEIGHT-$BALL_DIAMETR),$MIN_SPEED+rand($MAX_SPEED),$MIN_SPEED+rand($MAX_SPEED),true) # Синього кольору, розташований праворуч від перешкоди, # у випадковій точці, з випадковою швидкістю Ball.new(rand($EFFECTIVE_WIDTH_WALL_LEFT),rand($SCREEN_HEIGHT-$BALL_DIAMETR),$MIN_SPEED+rand($MAX_SPEED),$MIN_SPEED+rand($MAX_SPEED),false) end t = true # Ініціалізація змінної-прапору існування перешкоди time = Time.now # Ініціалізація допоміжної змінної для збереження часу початку роботи # 5. Цикл оновлення екрану update do # Оновлення екрану приблизно 60 разів на секунду # Виклик статичного методу all_instances класу Ball і послідовне # застосування наступного блоку вказівок для кожного еземпляру і Ball.all_instances.each do |i| if (t) and (Time.now - time > $WALL_TIME) # Якщо час існування перешкоди минув t = false # Зняття прапора wall.remove # Видалення перешкоди end i.move(t) # Застосування методу зміни розташування end end # 6. Показ вікна програми show # Виведення зображення на екран