Finish, mudinji pochi
This commit is contained in:
parent
d758d03f2d
commit
c551715a52
@ -4,6 +4,8 @@ Goal: Generate 'hard' puzzles.
|
|||||||
|
|
||||||
### Play a demo of the game [here](https://games.neophyte.me/sol_chess/)
|
### Play a demo of the game [here](https://games.neophyte.me/sol_chess/)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
- Install Rust from [here](https://www.rust-lang.org/tools/install).
|
- Install Rust from [here](https://www.rust-lang.org/tools/install).
|
||||||
|
BIN
img/sol_chess.png
Normal file
BIN
img/sol_chess.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 271 KiB |
132
src/game.rs
132
src/game.rs
@ -3,8 +3,10 @@ use std::{
|
|||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use button::{Button, ButtonColor};
|
use button::Button;
|
||||||
|
use color::UiColor;
|
||||||
use macroquad::{math, prelude::*, rand};
|
use macroquad::{math, prelude::*, rand};
|
||||||
|
use shadow::draw_shadow;
|
||||||
use sol_chess::{
|
use sol_chess::{
|
||||||
board::{Board, BoardState},
|
board::{Board, BoardState},
|
||||||
generator::{self, RandomRange},
|
generator::{self, RandomRange},
|
||||||
@ -12,6 +14,8 @@ use sol_chess::{
|
|||||||
use texture::PieceTexture;
|
use texture::PieceTexture;
|
||||||
|
|
||||||
pub mod button;
|
pub mod button;
|
||||||
|
pub mod color;
|
||||||
|
pub mod shadow;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
|
||||||
pub struct MacroquadRandAdapter;
|
pub struct MacroquadRandAdapter;
|
||||||
@ -43,11 +47,14 @@ pub struct Game {
|
|||||||
square_width: f32,
|
square_width: f32,
|
||||||
window_height: f32,
|
window_height: f32,
|
||||||
window_width: f32,
|
window_width: f32,
|
||||||
|
board_rect: Rect,
|
||||||
squares: Vec<GameSquare>,
|
squares: Vec<GameSquare>,
|
||||||
heading_rect: Rect,
|
heading_rect: Rect,
|
||||||
heading_font_size: f32,
|
heading_font_size: f32,
|
||||||
gp_btns: HashMap<ButtonAction, Button>,
|
gp_btns: HashMap<ButtonAction, Button>,
|
||||||
mode_btns: HashMap<GameMode, Button>,
|
mode_btns: HashMap<GameMode, Button>,
|
||||||
|
rules: bool,
|
||||||
|
rules_btn: Vec<Button>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GameSquare {
|
struct GameSquare {
|
||||||
@ -89,6 +96,7 @@ impl Game {
|
|||||||
Self {
|
Self {
|
||||||
original_board: board.clone(),
|
original_board: board.clone(),
|
||||||
board,
|
board,
|
||||||
|
board_rect: Rect::new(0., 0., 0., 0.),
|
||||||
squares: Vec::new(),
|
squares: Vec::new(),
|
||||||
heading_rect: Rect::new(0., 0., 0., 0.),
|
heading_rect: Rect::new(0., 0., 0., 0.),
|
||||||
heading_text: "Solitaire Chess".to_string(),
|
heading_text: "Solitaire Chess".to_string(),
|
||||||
@ -100,6 +108,8 @@ impl Game {
|
|||||||
debug: false,
|
debug: false,
|
||||||
gp_btns: HashMap::new(),
|
gp_btns: HashMap::new(),
|
||||||
mode_btns: HashMap::new(),
|
mode_btns: HashMap::new(),
|
||||||
|
rules: false,
|
||||||
|
rules_btn: Vec::new(),
|
||||||
window_height: 0.,
|
window_height: 0.,
|
||||||
window_width: 0.,
|
window_width: 0.,
|
||||||
square_width: 0.,
|
square_width: 0.,
|
||||||
@ -127,29 +137,54 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_input(&mut self) {
|
pub fn handle_input(&mut self) {
|
||||||
let mut btn_clicked = None;
|
let mut gp_btn_clicked = None;
|
||||||
for btn in &mut self.gp_btns {
|
for btn in &mut self.gp_btns {
|
||||||
btn.1.handle_input();
|
btn.1.handle_input();
|
||||||
if btn.1.is_clicked() {
|
if btn.1.is_clicked() {
|
||||||
btn_clicked = Some(btn.0.clone());
|
gp_btn_clicked = Some(btn.0.clone());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(action) = btn_clicked {
|
if let Some(action) = gp_btn_clicked {
|
||||||
match action {
|
match action {
|
||||||
ButtonAction::Reset => self.reset(),
|
ButtonAction::Reset => self.reset(),
|
||||||
ButtonAction::Next => self.next_puzzle(),
|
ButtonAction::Next => self.next_puzzle(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let mut mode_btn_clicked = None;
|
||||||
for btn in &mut self.mode_btns {
|
for btn in &mut self.mode_btns {
|
||||||
btn.1.handle_input();
|
btn.1.handle_input();
|
||||||
if btn.1.is_clicked() {
|
if btn.1.is_clicked() {
|
||||||
self.game_mode = *btn.0;
|
mode_btn_clicked = Some(btn);
|
||||||
self.next_puzzle();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(btn) = mode_btn_clicked {
|
||||||
|
self.game_mode = *btn.0;
|
||||||
|
self.next_puzzle();
|
||||||
|
} else {
|
||||||
|
let mut rules_btn_clicked = false;
|
||||||
|
for btn in &mut self.rules_btn {
|
||||||
|
btn.handle_input();
|
||||||
|
if btn.is_clicked() {
|
||||||
|
rules_btn_clicked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rules_btn_clicked {
|
||||||
|
self.rules = !self.rules;
|
||||||
|
if self.rules {
|
||||||
|
self.rules_btn[0].text = "Close".to_string();
|
||||||
|
self.rules_btn[0].color = UiColor::Green;
|
||||||
|
} else {
|
||||||
|
self.rules_btn[0].text = "Rules".to_string();
|
||||||
|
self.rules_btn[0].color = UiColor::Brown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for btn in &mut self.mode_btns {
|
for btn in &mut self.mode_btns {
|
||||||
@ -160,6 +195,11 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_key_released(KeyCode::Escape) {
|
||||||
|
self.rules = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if is_key_released(KeyCode::D) {
|
if is_key_released(KeyCode::D) {
|
||||||
self.debug = !self.debug;
|
self.debug = !self.debug;
|
||||||
return;
|
return;
|
||||||
@ -218,15 +258,45 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_board(&self) {
|
fn draw_board(&self) {
|
||||||
|
let board_shadow_width = 0.1 * self.square_width;
|
||||||
|
draw_shadow(self.board_rect, board_shadow_width);
|
||||||
|
|
||||||
|
if self.rules {
|
||||||
|
draw_rectangle(
|
||||||
|
self.board_rect.x,
|
||||||
|
self.board_rect.y,
|
||||||
|
self.board_rect.w,
|
||||||
|
self.board_rect.h,
|
||||||
|
UiColor::Brown.to_bg_color(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let font_size = self.heading_font_size * 0.8;
|
||||||
|
let rules = "\
|
||||||
|
Every move should be a \n\
|
||||||
|
capture. Win when only \n\
|
||||||
|
one piece is left.\n";
|
||||||
|
let measurement = measure_text(rules, None, font_size as u16, 1.0);
|
||||||
|
draw_multiline_text(
|
||||||
|
rules,
|
||||||
|
self.board_rect.x + 0.05 * self.square_width,
|
||||||
|
self.board_rect.y + 0.5 * (self.board_rect.h - measurement.height)
|
||||||
|
- 2. * measurement.offset_y,
|
||||||
|
font_size,
|
||||||
|
Some(2.),
|
||||||
|
UiColor::Brown.to_fg_color(),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let sprite_size = 0.8 * self.square_width;
|
let sprite_size = 0.8 * self.square_width;
|
||||||
let mut selected_square = None;
|
let mut selected_square = None;
|
||||||
self.squares.iter().for_each(|square| {
|
self.squares.iter().for_each(|square| {
|
||||||
let color = if square.is_source {
|
let color = match square.is_source {
|
||||||
Color::from_rgba(112, 105, 141, 255)
|
true => square.color,
|
||||||
} else if square.is_target {
|
false => match square.is_target {
|
||||||
Color::from_rgba(112, 150, 141, 255)
|
true => UiColor::Pink.to_shadow_color(),
|
||||||
} else {
|
false => square.color,
|
||||||
square.color
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
draw_rectangle(
|
draw_rectangle(
|
||||||
@ -276,6 +346,10 @@ impl Game {
|
|||||||
for btn in &self.mode_btns {
|
for btn in &self.mode_btns {
|
||||||
btn.1.draw();
|
btn.1.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for btn in &self.rules_btn {
|
||||||
|
btn.draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_debug(&self) {
|
fn draw_debug(&self) {
|
||||||
@ -310,6 +384,7 @@ impl Game {
|
|||||||
let board_width = self.square_width * self.num_squares as f32;
|
let board_width = self.square_width * self.num_squares as f32;
|
||||||
let board_x = (self.window_width - board_width) / 2.0;
|
let board_x = (self.window_width - board_width) / 2.0;
|
||||||
let board_y = (self.window_height - board_width) / 2.0;
|
let board_y = (self.window_height - board_width) / 2.0;
|
||||||
|
self.board_rect = Rect::new(board_x, board_y, board_width, board_width);
|
||||||
|
|
||||||
self.heading_font_size = 0.07 * min_dimension;
|
self.heading_font_size = 0.07 * min_dimension;
|
||||||
let f = self.heading_font_size.floor() as u16;
|
let f = self.heading_font_size.floor() as u16;
|
||||||
@ -321,8 +396,8 @@ impl Game {
|
|||||||
dims.height,
|
dims.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
let dark = Color::from_rgba(83, 104, 120, 255);
|
let dark = UiColor::Brown.to_bg_color();
|
||||||
let light = Color::from_rgba(190, 190, 190, 255);
|
let light = UiColor::Yellow.to_bg_color();
|
||||||
let mut rects = Vec::new();
|
let mut rects = Vec::new();
|
||||||
for i in 0..self.num_squares {
|
for i in 0..self.num_squares {
|
||||||
for j in 0..self.num_squares {
|
for j in 0..self.num_squares {
|
||||||
@ -356,7 +431,7 @@ impl Game {
|
|||||||
let reset_btn = Button::new(
|
let reset_btn = Button::new(
|
||||||
"Reset",
|
"Reset",
|
||||||
Rect::new(board_x + btn_x_offset, btn_y, btn_w, btn_h),
|
Rect::new(board_x + btn_x_offset, btn_y, btn_w, btn_h),
|
||||||
ButtonColor::Red,
|
UiColor::Yellow,
|
||||||
);
|
);
|
||||||
let mut next_btn = Button::new(
|
let mut next_btn = Button::new(
|
||||||
"Next",
|
"Next",
|
||||||
@ -366,11 +441,22 @@ impl Game {
|
|||||||
btn_w,
|
btn_w,
|
||||||
btn_h,
|
btn_h,
|
||||||
),
|
),
|
||||||
ButtonColor::Green,
|
UiColor::Green,
|
||||||
);
|
);
|
||||||
|
|
||||||
next_btn.is_active = false;
|
next_btn.is_active = false;
|
||||||
|
|
||||||
|
let rules_button = Button::new(
|
||||||
|
"Rules",
|
||||||
|
Rect::new(
|
||||||
|
(board_x - btn_w) / 2.,
|
||||||
|
board_y + (self.square_width - btn_h) / 2.,
|
||||||
|
btn_w,
|
||||||
|
btn_h,
|
||||||
|
),
|
||||||
|
UiColor::Brown,
|
||||||
|
);
|
||||||
|
self.rules_btn = vec![rules_button];
|
||||||
|
|
||||||
self.gp_btns = HashMap::new();
|
self.gp_btns = HashMap::new();
|
||||||
self.gp_btns.insert(ButtonAction::Next, next_btn);
|
self.gp_btns.insert(ButtonAction::Next, next_btn);
|
||||||
self.gp_btns.insert(ButtonAction::Reset, reset_btn);
|
self.gp_btns.insert(ButtonAction::Reset, reset_btn);
|
||||||
@ -379,33 +465,33 @@ impl Game {
|
|||||||
"Easy",
|
"Easy",
|
||||||
Rect::new(
|
Rect::new(
|
||||||
(board_x - btn_w) / 2.,
|
(board_x - btn_w) / 2.,
|
||||||
board_y + (self.square_width - btn_h) / 2.,
|
board_y + self.square_width + (self.square_width - btn_h) / 2.,
|
||||||
btn_w,
|
btn_w,
|
||||||
btn_h,
|
btn_h,
|
||||||
),
|
),
|
||||||
ButtonColor::Blue,
|
UiColor::Yellow,
|
||||||
);
|
);
|
||||||
|
|
||||||
let medium_btn = Button::new(
|
let medium_btn = Button::new(
|
||||||
"Medium",
|
"Medium",
|
||||||
Rect::new(
|
Rect::new(
|
||||||
(board_x - btn_w) / 2.,
|
(board_x - btn_w) / 2.,
|
||||||
board_y + self.square_width + (self.square_width - btn_h) / 2.,
|
board_y + 2. * self.square_width + (self.square_width - btn_h) / 2.,
|
||||||
btn_w,
|
btn_w,
|
||||||
btn_h,
|
btn_h,
|
||||||
),
|
),
|
||||||
ButtonColor::Blue,
|
UiColor::Yellow,
|
||||||
);
|
);
|
||||||
|
|
||||||
let hard_button = Button::new(
|
let hard_button = Button::new(
|
||||||
"Hard",
|
"Hard",
|
||||||
Rect::new(
|
Rect::new(
|
||||||
(board_x - btn_w) / 2.,
|
(board_x - btn_w) / 2.,
|
||||||
board_y + 2. * self.square_width + (self.square_width - btn_h) / 2.,
|
board_y + 3. * self.square_width + (self.square_width - btn_h) / 2.,
|
||||||
btn_w,
|
btn_w,
|
||||||
btn_h,
|
btn_h,
|
||||||
),
|
),
|
||||||
ButtonColor::Blue,
|
UiColor::Yellow,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.mode_btns = HashMap::new();
|
self.mode_btns = HashMap::new();
|
||||||
|
@ -1,45 +1,19 @@
|
|||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
|
use super::{color::UiColor, shadow::draw_shadow};
|
||||||
|
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
pub is_active: bool,
|
pub is_active: bool,
|
||||||
text: String,
|
pub text: String,
|
||||||
is_down: bool,
|
is_down: bool,
|
||||||
is_clicked: bool,
|
is_clicked: bool,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
shadow_width: f32,
|
shadow_width: f32,
|
||||||
color: ButtonColor,
|
pub color: UiColor,
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ButtonColor {
|
|
||||||
Grey,
|
|
||||||
Green,
|
|
||||||
Red,
|
|
||||||
Blue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ButtonColor {
|
|
||||||
fn to_bg_color(&self) -> Color {
|
|
||||||
match self {
|
|
||||||
ButtonColor::Grey => Color::from_rgba(140, 140, 140, 200),
|
|
||||||
ButtonColor::Green => Color::from_rgba(112, 140, 141, 200),
|
|
||||||
ButtonColor::Red => Color::from_rgba(123, 70, 85, 200),
|
|
||||||
ButtonColor::Blue => Color::from_rgba(140, 120, 250, 200),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_shadow_color(&self) -> Color {
|
|
||||||
let bg_color = self.to_bg_color();
|
|
||||||
Color::from_rgba(
|
|
||||||
(bg_color.r * 255.) as u8,
|
|
||||||
(bg_color.g * 255.) as u8,
|
|
||||||
(bg_color.b * 255.) as u8,
|
|
||||||
100,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Button {
|
impl Button {
|
||||||
pub fn new(text: &str, rect: Rect, color: ButtonColor) -> Self {
|
pub fn new(text: &str, rect: Rect, color: UiColor) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text: text.to_string(),
|
text: text.to_string(),
|
||||||
is_down: false,
|
is_down: false,
|
||||||
@ -68,9 +42,8 @@ impl Button {
|
|||||||
fn draw_button(&self) {
|
fn draw_button(&self) {
|
||||||
let bg_color = match self.is_active {
|
let bg_color = match self.is_active {
|
||||||
true => self.color.to_bg_color(),
|
true => self.color.to_bg_color(),
|
||||||
false => ButtonColor::Grey.to_bg_color(),
|
false => self.color.to_shadow_color(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let button_draw_offset = self.get_button_draw_offset();
|
let button_draw_offset = self.get_button_draw_offset();
|
||||||
draw_rectangle(
|
draw_rectangle(
|
||||||
self.rect.x + button_draw_offset,
|
self.rect.x + button_draw_offset,
|
||||||
@ -92,47 +65,12 @@ impl Button {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = self.color.to_shadow_color();
|
draw_shadow(self.rect, self.shadow_width);
|
||||||
draw_rectangle(
|
|
||||||
self.rect.x + self.rect.w,
|
|
||||||
self.rect.y + self.shadow_width,
|
|
||||||
self.shadow_width,
|
|
||||||
self.rect.h,
|
|
||||||
color,
|
|
||||||
);
|
|
||||||
|
|
||||||
draw_rectangle(
|
|
||||||
self.rect.x + self.shadow_width,
|
|
||||||
self.rect.y + self.rect.h,
|
|
||||||
self.rect.w - self.shadow_width,
|
|
||||||
self.shadow_width,
|
|
||||||
color,
|
|
||||||
);
|
|
||||||
|
|
||||||
draw_triangle(
|
|
||||||
vec2(self.rect.x + self.rect.w, self.rect.y),
|
|
||||||
vec2(
|
|
||||||
self.rect.x + self.rect.w + self.shadow_width,
|
|
||||||
self.rect.y + self.shadow_width,
|
|
||||||
),
|
|
||||||
vec2(self.rect.x + self.rect.w, self.rect.y + self.shadow_width),
|
|
||||||
color,
|
|
||||||
);
|
|
||||||
|
|
||||||
draw_triangle(
|
|
||||||
vec2(self.rect.x, self.rect.y + self.rect.h),
|
|
||||||
vec2(
|
|
||||||
self.rect.x + self.shadow_width,
|
|
||||||
self.rect.y + self.rect.h + self.shadow_width,
|
|
||||||
),
|
|
||||||
vec2(self.rect.x + self.shadow_width, self.rect.y + self.rect.h),
|
|
||||||
color,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_label(&self) {
|
fn draw_label(&self) {
|
||||||
let font_color = match self.is_active {
|
let font_color = match self.is_active {
|
||||||
true => Color::from_rgba(0, 0, 0, 255),
|
true => self.color.to_fg_color(),
|
||||||
false => Color::from_rgba(100, 100, 100, 255),
|
false => Color::from_rgba(100, 100, 100, 255),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
45
src/game/color.rs
Normal file
45
src/game/color.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum UiColor {
|
||||||
|
Grey,
|
||||||
|
Green,
|
||||||
|
Pink,
|
||||||
|
Brown,
|
||||||
|
Yellow,
|
||||||
|
Blue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UiColor {
|
||||||
|
pub fn to_bg_color(&self) -> Color {
|
||||||
|
match self {
|
||||||
|
UiColor::Grey => Color::from_rgba(140, 140, 140, 200),
|
||||||
|
UiColor::Green => Color::from_rgba(16, 60, 50, 200),
|
||||||
|
UiColor::Pink => Color::from_rgba(234, 128, 71, 200),
|
||||||
|
UiColor::Brown => Color::from_rgba(123, 61, 35, 200),
|
||||||
|
UiColor::Yellow => Color::from_rgba(242, 230, 190, 200),
|
||||||
|
UiColor::Blue => Color::from_rgba(47, 85, 172, 200),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_fg_color(&self) -> Color {
|
||||||
|
match self {
|
||||||
|
UiColor::Grey => Color::from_rgba(255, 255, 255, 200),
|
||||||
|
UiColor::Green => Color::from_rgba(255, 255, 255, 200),
|
||||||
|
UiColor::Pink => Color::from_rgba(255, 255, 255, 200),
|
||||||
|
UiColor::Brown => Color::from_rgba(255, 255, 255, 200),
|
||||||
|
UiColor::Yellow => Color::from_rgba(0, 0, 0, 200),
|
||||||
|
UiColor::Blue => Color::from_rgba(255, 255, 255, 200),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_shadow_color(&self) -> Color {
|
||||||
|
let bg_color = self.to_bg_color();
|
||||||
|
Color::from_rgba(
|
||||||
|
(bg_color.r * 255.) as u8,
|
||||||
|
(bg_color.g * 255.) as u8,
|
||||||
|
(bg_color.b * 255.) as u8,
|
||||||
|
100,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
20
src/game/shadow.rs
Normal file
20
src/game/shadow.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
|
pub fn draw_shadow(rect: Rect, shadow_width: f32) {
|
||||||
|
let shadow_color = Color::new(0., 0., 0., 0.8);
|
||||||
|
draw_rectangle(
|
||||||
|
rect.x + rect.w,
|
||||||
|
rect.y + shadow_width,
|
||||||
|
shadow_width,
|
||||||
|
rect.h,
|
||||||
|
shadow_color,
|
||||||
|
);
|
||||||
|
|
||||||
|
draw_rectangle(
|
||||||
|
rect.x + shadow_width,
|
||||||
|
rect.y + rect.h,
|
||||||
|
rect.w - shadow_width,
|
||||||
|
shadow_width,
|
||||||
|
shadow_color,
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user