ユーザ用ツール

サイト用ツール


youtube:sfml-bricks

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
youtube:sfml-bricks [2024/02/28 18:26] – 削除 - 外部編集 (不明な日付) 127.0.0.1youtube:sfml-bricks [2024/02/28 18:34] (現在) – ↷ 移動操作に合わせてリンクを書き換えました。 freemikan
行 1: 行 1:
 +====== ブロック崩し ======
 +
 +作成日: 2022-12-10 (土)
 +
 +{{youtube:sfml-bricks.png?400|}}
 +
 +
 +src/main.rs
 +
 +<file rust>
 +use sfml::{graphics::*, system::*, window::*};
 +
 +struct MoveFlags {
 +    left: bool,
 +    right: bool,
 +}
 +
 +type Brick<'a> = RectangleShape<'a>;
 +
 +struct Game<'a> {
 +    window: RenderWindow,
 +    paddle: RectangleShape<'a>,
 +    paddle_speed: f32,
 +    ball: CircleShape<'a>,
 +    ball_velocity: Vector2f,
 +    move_flags: MoveFlags,
 +    bricks: Vec<Brick<'a>>,
 +}
 +
 +impl<'a> Game<'a> {
 +    const FPS: f32 = 60.0; // Time::seconds(1.0 / 60.0) is not allowed for const
 +    const WIDTH: u32 = 1000;
 +    const HEIGHT: u32 = 800;
 +    const PADDLE_SPEED: f32 = 300.0;
 +    const PADDLE_SIZE_X: f32 = 100.0;
 +    const PADDLE_SIZE_Y: f32 = 30.0;
 +    const BALL_SPEED: f32 = 600.0;
 +    const BALL_RADIUS: f32 = 15.0;
 +    const BRICK_COUNT_X: u32 = 10;
 +    const BRICK_COUNT_Y: u32 = 8;
 +
 +    pub fn new() -> Game<'a> {
 +        let window = RenderWindow::new(
 +            (Self::WIDTH, Self::HEIGHT),
 +            "Pong with Rust and SFML",
 +            Style::CLOSE,
 +            &Default::default(),
 +        );
 +
 +        // setup paddle
 +        let paddle = RectangleShape::from_rect(FloatRect {
 +            left: (Self::WIDTH as f32 / 2.0) - Self::PADDLE_SIZE_X / 2.0,
 +            top: Self::HEIGHT as f32 - Self::PADDLE_SIZE_Y * 2.0,
 +            width: Self::PADDLE_SIZE_X,
 +            height: Self::PADDLE_SIZE_Y,
 +        });
 +
 +        let paddle_speed = Self::PADDLE_SPEED;
 +
 +        // setup ball
 +        let mut ball = CircleShape::new(Self::BALL_RADIUS, 30);
 +        ball.set_position((Self::WIDTH as f32 / 2.0, Self::HEIGHT as f32 / 2.0));
 +        ball.set_origin((Self::BALL_RADIUS, Self::BALL_RADIUS));
 +
 +        let ball_velocity = Vector2f::new(Self::BALL_SPEED, Self::BALL_SPEED);
 +
 +        // 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::BRICK_COUNT_X + 1) as f32 + Self::BRICK_COUNT_X as f32);
 +        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::with_capacity(Self::BRICK_COUNT_X as usize * Self::BRICK_COUNT_Y as usize);
 +        for i in 0..Self::BRICK_COUNT_Y {
 +            for j in 0..Self::BRICK_COUNT_X {
 +                let mut brick = Brick::from_rect(FloatRect {
 +                    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::rgb(
 +                    ((Self::BRICK_COUNT_X - j) * (255 / Self::BRICK_COUNT_X)) as u8,
 +                    ((i + 1) * (255 / Self::BRICK_COUNT_Y)) as u8,
 +                    ((j + 1) * (255 / Self::BRICK_COUNT_X)) as u8,
 +                ));
 +
 +                bricks.push(brick);
 +            }
 +        }
 +
 +        Self {
 +            window,
 +            paddle,
 +            paddle_speed,
 +            ball,
 +            ball_velocity,
 +            move_flags: MoveFlags {
 +                left: false,
 +                right: false,
 +            },
 +            bricks,
 +        }
 +    }
 +
 +    pub fn run(&mut self) {
 +        let mut clock = Clock::start();
 +        let mut time_since_last_update = Time::ZERO;
 +        let time_per_frame = Time::seconds(1.0 / Self::FPS);
 +
 +        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(&time_per_frame);
 +            }
 +            self.render();
 +        }
 +    }
 +
 +    fn process_events(&mut self) {
 +        while let Some(event) = self.window.poll_event() {
 +            match event {
 +                Event::Closed => self.window.close(),
 +                Event::KeyPressed { code, .. } => {
 +                    if code == Key::Enter || code == Key::Escape {
 +                        self.window.close();
 +                    } else {
 +                        self.handle_player_input(code, true);
 +                    }
 +                }
 +                Event::KeyReleased { code, .. } => self.handle_player_input(code, false),
 +                _ => {}
 +            }
 +        }
 +    }
 +
 +    fn update(&mut self, delta_time: &Time) {
 +        self.update_paddle(delta_time);
 +        self.update_ball(delta_time);
 +    }
 +
 +    fn update_paddle(&mut self, delta_time: &Time) {
 +        let mut movement = Vector2f::new(0.0, 0.0);
 +
 +        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(&mut self, delta_time: &Time) {
 +        self.update_ball_x(delta_time);
 +        self.update_ball_y(delta_time);
 +    }
 +
 +    fn update_ball_x(&mut self, delta_time: &Time) {
 +        self.ball
 +            .move_((self.ball_velocity.x * delta_time.as_seconds(), 0.0));
 +
 +        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(), self.ball.position().y));
 +        }
 +
 +        let paddle_rect = self.paddle.global_bounds();
 +        let ball_rect = self.ball.global_bounds();
 +        let mut hit = false;
 +
 +        if ball_rect.intersection(&paddle_rect) != None {
 +            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(&brick_rect) != None {
 +                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(&mut self, delta_time: &Time) {
 +        self.ball
 +            .move_((0.0, self.ball_velocity.y * delta_time.as_seconds()));
 +
 +        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, self.ball.radius()));
 +        }
 +
 +        if self.ball.position().y + self.ball.radius() > Self::HEIGHT as f32 {
 +            // align to bottom of screen
 +            self.ball_velocity.y *= -1.0;
 +            self.ball.set_position((
 +                self.ball.position().x,
 +                Self::HEIGHT as f32 - 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(&paddle_rect) != None {
 +            if self.ball_velocity.y < 0.0 {
 +                // align to bottom of paddle
 +                self.ball
 +                    .set_position((self.ball.position().x, paddle_rect.top + paddle_rect.height));
 +            } else {
 +                // align to top of paddle
 +                self.ball
 +                    .set_position((self.ball.position().x, paddle_rect.top - self.ball.radius()));
 +            }
 +
 +            hit = true;
 +        }
 +
 +        self.bricks.retain(|b| {
 +            let brick_rect = b.global_bounds();
 +            if ball_rect.intersection(&brick_rect) != None {
 +                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(&mut self) {
 +        self.window.clear(Color::BLUE);
 +        self.window.draw(&self.paddle);
 +        self.window.draw(&self.ball);
 +        for brick in &self.bricks {
 +            self.window.draw(brick);
 +        }
 +        self.window.display();
 +    }
 +
 +    fn handle_player_input(&mut self, code: Key, pressed: bool) {
 +        match code {
 +            Key::Left => self.move_flags.left = pressed,
 +            Key::Right => self.move_flags.right = pressed,
 +            _ => {}
 +        }
 +    }
 +}
 +
 +fn main() {
 +    let mut game = Game::new();
 +    game.run();
 +}
 +
 +</file>
 +
 +Cargo.toml
 +
 +<file>
 +[package]
 +name = "bricks"
 +version = "0.1.0"
 +edition = "2021"
 +
 +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 +
 +[dependencies]
 +sfml = "0.19.0"
 +</file>
  

特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki