差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
| youtube:sfml-bricks [2024/02/28 18:26] – 削除 - 外部編集 (不明な日付) 127.0.0.1 | youtube:sfml-bricks [2024/02/28 18:34] (現在) – ↷ 移動操作に合わせてリンクを書き換えました。 freemikan | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| + | ====== ブロック崩し ====== | ||
| + | |||
| + | 作成日: 2022-12-10 (土) | ||
| + | |||
| + | {{youtube: | ||
| + | |||
| + | |||
| + | src/main.rs | ||
| + | |||
| + | <file rust> | ||
| + | use sfml:: | ||
| + | |||
| + | struct MoveFlags { | ||
| + | left: bool, | ||
| + | right: bool, | ||
| + | } | ||
| + | |||
| + | type Brick<' | ||
| + | |||
| + | struct Game<' | ||
| + | window: RenderWindow, | ||
| + | paddle: RectangleShape<' | ||
| + | paddle_speed: | ||
| + | ball: CircleShape<' | ||
| + | ball_velocity: | ||
| + | move_flags: MoveFlags, | ||
| + | bricks: Vec< | ||
| + | } | ||
| + | |||
| + | impl<' | ||
| + | const FPS: f32 = 60.0; // Time:: | ||
| + | const WIDTH: u32 = 1000; | ||
| + | const HEIGHT: u32 = 800; | ||
| + | const PADDLE_SPEED: | ||
| + | const PADDLE_SIZE_X: | ||
| + | const PADDLE_SIZE_Y: | ||
| + | const BALL_SPEED: f32 = 600.0; | ||
| + | const BALL_RADIUS: | ||
| + | const BRICK_COUNT_X: | ||
| + | const BRICK_COUNT_Y: | ||
| + | |||
| + | pub fn new() -> Game<' | ||
| + | let window = RenderWindow:: | ||
| + | (Self:: | ||
| + | "Pong with Rust and SFML", | ||
| + | Style:: | ||
| + | & | ||
| + | ); | ||
| + | |||
| + | // setup paddle | ||
| + | let paddle = RectangleShape:: | ||
| + | left: (Self:: | ||
| + | top: Self:: | ||
| + | width: Self:: | ||
| + | height: Self:: | ||
| + | }); | ||
| + | |||
| + | let paddle_speed = Self:: | ||
| + | |||
| + | // setup ball | ||
| + | let mut ball = CircleShape:: | ||
| + | ball.set_position((Self:: | ||
| + | ball.set_origin((Self:: | ||
| + | |||
| + | let ball_velocity = Vector2f:: | ||
| + | |||
| + | // setup bricks | ||
| + | |||
| + | // calc brick and gap size | ||
| + | // g = r*b | ||
| + | // w = r*b*(n+1) + b*n | ||
| + | // w = b*{r*(n+1) + n} | ||
| + | // b = w / {r*(n+1) + n} | ||
| + | let gap_ratio = 1.0 / 8.0; | ||
| + | let brick_width = Self::WIDTH as f32 | ||
| + | / (gap_ratio * (Self:: | ||
| + | let gap = brick_width * gap_ratio; | ||
| + | let brick_yx_ratio = 1.0 / 3.0; | ||
| + | let brick_height = brick_width * brick_yx_ratio; | ||
| + | |||
| + | let mut bricks = | ||
| + | Vec:: | ||
| + | for i in 0..Self:: | ||
| + | for j in 0..Self:: | ||
| + | let mut brick = Brick:: | ||
| + | left: gap + j as f32 * (gap + brick_width), | ||
| + | top: gap + i as f32 * (gap + brick_height), | ||
| + | width: brick_width, | ||
| + | height: brick_height, | ||
| + | }); | ||
| + | |||
| + | brick.set_fill_color(Color:: | ||
| + | ((Self:: | ||
| + | ((i + 1) * (255 / Self:: | ||
| + | ((j + 1) * (255 / Self:: | ||
| + | )); | ||
| + | |||
| + | bricks.push(brick); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Self { | ||
| + | window, | ||
| + | paddle, | ||
| + | paddle_speed, | ||
| + | ball, | ||
| + | ball_velocity, | ||
| + | move_flags: MoveFlags { | ||
| + | left: false, | ||
| + | right: false, | ||
| + | }, | ||
| + | bricks, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | pub fn run(& | ||
| + | let mut clock = Clock:: | ||
| + | let mut time_since_last_update = Time::ZERO; | ||
| + | let time_per_frame = Time:: | ||
| + | |||
| + | while self.window.is_open() { | ||
| + | self.process_events(); | ||
| + | |||
| + | time_since_last_update += clock.restart(); | ||
| + | while time_since_last_update > time_per_frame { | ||
| + | time_since_last_update -= time_per_frame; | ||
| + | self.process_events(); | ||
| + | self.update(& | ||
| + | } | ||
| + | self.render(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn process_events(& | ||
| + | while let Some(event) = self.window.poll_event() { | ||
| + | match event { | ||
| + | Event:: | ||
| + | Event:: | ||
| + | if code == Key::Enter || code == Key::Escape { | ||
| + | self.window.close(); | ||
| + | } else { | ||
| + | self.handle_player_input(code, | ||
| + | } | ||
| + | } | ||
| + | Event:: | ||
| + | _ => {} | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn update(& | ||
| + | self.update_paddle(delta_time); | ||
| + | self.update_ball(delta_time); | ||
| + | } | ||
| + | |||
| + | fn update_paddle(& | ||
| + | let mut movement = Vector2f:: | ||
| + | |||
| + | if self.move_flags.left { | ||
| + | if self.paddle.position().x > 0.0 { | ||
| + | movement.x -= self.paddle_speed; | ||
| + | } | ||
| + | } | ||
| + | if self.move_flags.right { | ||
| + | if self.paddle.position().x + self.paddle.size().x < Self::WIDTH as f32 { | ||
| + | movement.x += self.paddle_speed; | ||
| + | } | ||
| + | } | ||
| + | self.paddle.move_(movement * delta_time.as_seconds()); | ||
| + | } | ||
| + | |||
| + | fn update_ball(& | ||
| + | self.update_ball_x(delta_time); | ||
| + | self.update_ball_y(delta_time); | ||
| + | } | ||
| + | |||
| + | fn update_ball_x(& | ||
| + | self.ball | ||
| + | .move_((self.ball_velocity.x * delta_time.as_seconds(), | ||
| + | |||
| + | if self.ball.position().x + self.ball.radius() > Self::WIDTH as f32 { | ||
| + | self.ball_velocity.x *= -1.0; | ||
| + | // align to right of screen | ||
| + | self.ball.set_position(( | ||
| + | Self::WIDTH as f32 - self.ball.radius(), | ||
| + | self.ball.position().y, | ||
| + | )); | ||
| + | } | ||
| + | |||
| + | if self.ball.position().x - self.ball.radius() < 0.0 { | ||
| + | self.ball_velocity.x *= -1.0; | ||
| + | // align to left of screen | ||
| + | self.ball | ||
| + | .set_position((self.ball.radius(), | ||
| + | } | ||
| + | |||
| + | let paddle_rect = self.paddle.global_bounds(); | ||
| + | let ball_rect = self.ball.global_bounds(); | ||
| + | let mut hit = false; | ||
| + | |||
| + | if ball_rect.intersection(& | ||
| + | if self.ball_velocity.x < 0.0 { | ||
| + | // align ball to right of paddle | ||
| + | self.ball.set_position(( | ||
| + | paddle_rect.left + paddle_rect.width + self.ball.radius(), | ||
| + | self.ball.position().y, | ||
| + | )); | ||
| + | } else { | ||
| + | // align ball to left of paddle | ||
| + | self.ball.set_position(( | ||
| + | paddle_rect.left - self.ball.radius(), | ||
| + | self.ball.position().y, | ||
| + | )) | ||
| + | } | ||
| + | hit = true; | ||
| + | } | ||
| + | |||
| + | self.bricks.retain(|b| { | ||
| + | let brick_rect = b.global_bounds(); | ||
| + | if ball_rect.intersection(& | ||
| + | if self.ball_velocity.x < 0.0 { | ||
| + | // align to right of brick | ||
| + | self.ball.set_position(( | ||
| + | brick_rect.left + brick_rect.width + self.ball.radius(), | ||
| + | self.ball.position().y, | ||
| + | )); | ||
| + | } else { | ||
| + | // align to left of brick | ||
| + | self.ball.set_position(( | ||
| + | brick_rect.left - self.ball.radius(), | ||
| + | self.ball.position().y, | ||
| + | )); | ||
| + | } | ||
| + | hit = true; | ||
| + | false | ||
| + | } else { | ||
| + | true | ||
| + | } | ||
| + | }); | ||
| + | |||
| + | if hit { | ||
| + | self.ball_velocity.x *= -1.0; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn update_ball_y(& | ||
| + | self.ball | ||
| + | .move_((0.0, | ||
| + | |||
| + | if self.ball.position().y - self.ball.radius() < 0.0 { | ||
| + | // align to top of screen | ||
| + | self.ball_velocity.y *= -1.0; | ||
| + | self.ball | ||
| + | .set_position((self.ball.position().x, | ||
| + | } | ||
| + | |||
| + | if self.ball.position().y + self.ball.radius() > Self:: | ||
| + | // align to bottom of screen | ||
| + | self.ball_velocity.y *= -1.0; | ||
| + | self.ball.set_position(( | ||
| + | self.ball.position().x, | ||
| + | Self:: | ||
| + | )); | ||
| + | } | ||
| + | |||
| + | let paddle_rect = self.paddle.global_bounds(); | ||
| + | let ball_rect = self.ball.global_bounds(); | ||
| + | let mut hit = false; | ||
| + | |||
| + | if ball_rect.intersection(& | ||
| + | if self.ball_velocity.y < 0.0 { | ||
| + | // align to bottom of paddle | ||
| + | self.ball | ||
| + | .set_position((self.ball.position().x, | ||
| + | } else { | ||
| + | // align to top of paddle | ||
| + | self.ball | ||
| + | .set_position((self.ball.position().x, | ||
| + | } | ||
| + | |||
| + | hit = true; | ||
| + | } | ||
| + | |||
| + | self.bricks.retain(|b| { | ||
| + | let brick_rect = b.global_bounds(); | ||
| + | if ball_rect.intersection(& | ||
| + | if self.ball_velocity.y < 0.0 { | ||
| + | // align to bottom of brick | ||
| + | self.ball.set_position(( | ||
| + | self.ball.position().x, | ||
| + | brick_rect.top + brick_rect.height + self.ball.radius(), | ||
| + | )); | ||
| + | } else { | ||
| + | // align top top of brick | ||
| + | self.ball.set_position(( | ||
| + | self.ball.position().x, | ||
| + | brick_rect.top - self.ball.radius(), | ||
| + | )); | ||
| + | } | ||
| + | hit = true; | ||
| + | false | ||
| + | } else { | ||
| + | true | ||
| + | } | ||
| + | }); | ||
| + | |||
| + | if hit { | ||
| + | self.ball_velocity.y *= -1.0; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn render(& | ||
| + | self.window.clear(Color:: | ||
| + | self.window.draw(& | ||
| + | self.window.draw(& | ||
| + | for brick in & | ||
| + | self.window.draw(brick); | ||
| + | } | ||
| + | self.window.display(); | ||
| + | } | ||
| + | |||
| + | fn handle_player_input(& | ||
| + | match code { | ||
| + | Key::Left => self.move_flags.left = pressed, | ||
| + | Key::Right => self.move_flags.right = pressed, | ||
| + | _ => {} | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn main() { | ||
| + | let mut game = Game:: | ||
| + | game.run(); | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | Cargo.toml | ||
| + | |||
| + | < | ||
| + | [package] | ||
| + | name = " | ||
| + | version = " | ||
| + | edition = " | ||
| + | |||
| + | # See more keys and their definitions at https:// | ||
| + | |||
| + | [dependencies] | ||
| + | sfml = " | ||
| + | </ | ||
