Перейти к содержимому

Уроки · 83

Свой цвет

Давай соберём цвет сами, а не возьмём готовый. До сих пор мы брали цвета-константы вроде RED и GREEN, как в уроке «Разноцветные кружки», а в уроке «else if» выбирали из трёх таких цветов. Способов создать свой цвет в macroquad несколько, мы разберём один.

Свой цвет собирает Color::new. Ему нужно четыре числа от 0.0 до 1.0: сколько в цвете красного, зелёного и синего, а четвёртое число — непрозрачность. С ней пока всё просто: 1.0 значит «полностью непрозрачный», так и пишем.

// Красный, зелёный, синий и непрозрачность. Красный и зелёный вместе
// дают жёлтый.
let yellow = Color::new(1.0, 1.0, 0.0, 1.0);

Несколько примеров, чтобы почувствовать, как цвета смешиваются:

  • Color::new(1.0, 0.0, 0.0, 1.0) — красный.
  • Color::new(0.0, 1.0, 0.0, 1.0) — зелёный.
  • Color::new(1.0, 1.0, 0.0, 1.0) — жёлтый: красный и зелёный вместе.
  • Color::new(0.0, 0.0, 0.0, 1.0) — чёрный, а Color::new(1.0, 1.0, 1.0, 1.0) — белый.

Если число меньше 0, функция считает его за 0, а если больше 1, то за

  1. Так она работает. Например, Color::new(5.0, 0.0, 0.0, 1.0) даст тот же красный, что и Color::new(1.0, 0.0, 0.0, 1.0).

Теперь покрасим полоску из урока «Полоска здоровья» не ступеньками, а плавно. Возьмём долю здоровья fraction от 0 до 1, как в уроке «Доля от 0 до 1». Чем здоровья меньше, тем больше красного. Чем больше, тем больше зелёного:

// Красного столько, сколько здоровья не хватает, зелёного — сколько осталось.
let color = Color::new(1.0 - fraction, fraction, 0.0, 1.0);

Здоровье полное: fraction равно 1.0, красного 0.0, зелёного 1.0, получается чисто зелёный. Здоровья нет: красного 1.0, зелёного 0.0, получается чисто красный. А посередине красного и зелёного по 0.5, и цвет выходит тусклым.

Давай сделаем так, чтобы на середине оба цвета были на полную. Для этого удвоим оба числа:

// Умножаем на 2: всё, что больше 1.0, функция считает за 1.0.
let color = Color::new(2.0 * (1.0 - fraction), 2.0 * fraction, 0.0, 1.0);

При половине здоровья красного получается 2.0 * 0.5, то есть 1.0, и зелёного тоже 1.0: ярко-жёлтый. При полном здоровье зелёного получается 2.0, но функция считает его за 1.0, поэтому полоска всё так же чисто зелёная. Лишнее обрезается само, считать это не нужно.

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

Кликай по примеру: каждый клик отнимает здоровье, и цвет полоски меняется вместе с ним. Когда здоровье кончится, следующий клик вернёт его полностью. Меняй урон за клик, чтобы цвет менялся мельче или крупнее:

src/main.rs
use macroquad::prelude::*;
// Здоровье в начале и его максимум.
const MAX_HEALTH: f32 = 100.0;
// Сколько здоровья отнимает один клик.
const DAMAGE: f32 = 10.0;
// Левый верхний угол полоски, её высота и длина.
const BAR_X: f32 = 20.0;
const BAR_Y: f32 = 20.0;
const BAR_HEIGHT: f32 = 40.0;
const BAR_WIDTH: f32 = 400.0;
#[macroquad::main("Свой цвет")]
async fn main() {
// Текущее здоровье — сначала полное.
let mut health = MAX_HEALTH;
loop {
clear_background(BLACK);
// Кнопка мыши только что нажата.
if is_mouse_button_pressed(MouseButton::Left) {
if health <= 0.0 {
// Здоровья уже нет — возвращаем полное.
health = MAX_HEALTH;
} else {
// Отнимаем урон. max(0.0) не даёт здоровью уйти ниже нуля.
health = (health - DAMAGE).max(0.0);
}
}
// Доля здоровья от 0 до 1.
let fraction = health / MAX_HEALTH;
// Свой цвет: красного тем больше, чем меньше здоровья, а зелёного
// тем больше, чем здоровья больше. Умножаем на 2: числа больше 1.0
// функция считает за 1.0, поэтому посередине оба цвета на максимуме
// и получается ярко-жёлтый.
let color = Color::new(2.0 * (1.0 - fraction), 2.0 * fraction, 0.0, 1.0);
// Серая подложка: вся полоска целиком.
draw_rectangle(BAR_X, BAR_Y, BAR_WIDTH, BAR_HEIGHT, GRAY);
// Цветная часть поверх неё: ширина — доля от всей полоски.
draw_rectangle(BAR_X, BAR_Y, BAR_WIDTH * fraction, BAR_HEIGHT, color);
next_frame().await;
}
}
  • Color::new(r, g, b, a) собирает свой цвет из четырёх чисел от 0.0 до 1.0: красный, зелёный, синий и непрозрачность.
  • Непрозрачность 1.0 значит «полностью непрозрачный». Пока пишем её именно так.
  • Число меньше 0 функция считает за 0, а больше 1 за 1.
  • 1.0 - fraction растёт, когда здоровье падает, и даёт красный. fraction растёт вместе со здоровьем и даёт зелёный.
  • Умножение на 2 делает середину ярко-жёлтой, потому что лишнее обрезается.
  • Цвет теперь считается формулой, а не выбирается через if, поэтому меняется плавно.
  • damage — сколько здоровья отнимает клик. Чем он меньше, тем плавнее меняется цвет.