youtube:crsfml-pong
差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
youtube:crsfml-pong [2024/02/28 18:26] – 削除 - 外部編集 (不明な日付) 127.0.0.1 | youtube:crsfml-pong [2024/02/29 11:51] (現在) – freemikan | ||
---|---|---|---|
行 1: | 行 1: | ||
+ | ====== CrSFML Pong ====== | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== src/ | ||
+ | |||
+ | |||
+ | <file crystal> | ||
+ | require " | ||
+ | require " | ||
+ | |||
+ | GAME_WIDTH | ||
+ | GAME_HEIGHT | ||
+ | PADDLE_SPEED = 300.0_f32 | ||
+ | BALL_SPEED | ||
+ | |||
+ | alias ActionMap = Hash(String, | ||
+ | |||
+ | class Paddle < SF:: | ||
+ | include SF:: | ||
+ | |||
+ | def initialize(position : SF:: | ||
+ | color : SF::Color, speed : Float32, action_map : ActionMap) | ||
+ | super() | ||
+ | |||
+ | @shape = SF:: | ||
+ | @shape.origin = {size.x / 2, size.y / 2} | ||
+ | @shape.fill_color = color | ||
+ | |||
+ | @speed = speed | ||
+ | @action_map = action_map | ||
+ | @input_direction = SF.vector2f 0, 0 | ||
+ | |||
+ | self.position = position | ||
+ | end | ||
+ | |||
+ | def process_input | ||
+ | @input_direction.y = 0 | ||
+ | if SF:: | ||
+ | @input_direction.y = -1.0 | ||
+ | end | ||
+ | if SF:: | ||
+ | @input_direction.y = +1.0 | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def update(delta_time : SF::Time) | ||
+ | dy = @input_direction.y * @speed * delta_time.as_seconds | ||
+ | move 0, dy | ||
+ | |||
+ | rect = collision_rect | ||
+ | if top(rect) < 0 | ||
+ | self.position = {position.x, | ||
+ | end | ||
+ | if bottom(rect)> | ||
+ | self.position = {position.x, | ||
+ | | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def draw(target : SF:: | ||
+ | states.transform *= transform | ||
+ | target.draw @shape, states | ||
+ | end | ||
+ | |||
+ | def collision_rect : SF:: | ||
+ | SF:: | ||
+ | end | ||
+ | end | ||
+ | |||
+ | class Ball < SF:: | ||
+ | include SF:: | ||
+ | |||
+ | def initialize(position : SF:: | ||
+ | color : SF::Color, velocity : SF:: | ||
+ | super() | ||
+ | |||
+ | @shape = SF:: | ||
+ | @shape.origin = { radius, radius } | ||
+ | @shape.fill_color = color | ||
+ | |||
+ | @velocity = velocity | ||
+ | |||
+ | self.position = position | ||
+ | end | ||
+ | |||
+ | def update(delta_time : SF::Time, paddles : Array(Paddle)) | ||
+ | update_x delta_time, paddles | ||
+ | update_y delta_time, paddles | ||
+ | end | ||
+ | |||
+ | def draw(target : SF:: | ||
+ | states.transform *= transform | ||
+ | target.draw @shape, states | ||
+ | end | ||
+ | |||
+ | private def update_x(delta_time : SF::Time, paddles : Array(Paddle)) | ||
+ | dx = @velocity.x * delta_time.as_seconds | ||
+ | move dx, 0 | ||
+ | |||
+ | paddles.each do |p| | ||
+ | c = collision_circle | ||
+ | r = p.collision_rect | ||
+ | |||
+ | if circle_rect_collide? | ||
+ | if c.center.x > right(r) | ||
+ | self.position = {right(r) + @shape.origin.x, | ||
+ | @velocity.x *= -1 | ||
+ | elsif c.center.x < left(r) | ||
+ | self.position = {left(r) - 2 * c.radius + @shape.origin.x, | ||
+ | | ||
+ | @velocity.x *= -1 | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | c = collision_circle | ||
+ | if c.center.x - c.radius < 0 | ||
+ | @velocity.x = +@velocity.x.abs | ||
+ | end | ||
+ | if c.center.x + c.radius > GAME_WIDTH | ||
+ | @velocity.x = -@velocity.x.abs | ||
+ | end | ||
+ | end | ||
+ | |||
+ | private def update_y(delta_time : SF::Time, paddles : Array(Paddle)) | ||
+ | dy = @velocity.y * delta_time.as_seconds | ||
+ | move 0, dy | ||
+ | |||
+ | paddles.each do |p| | ||
+ | c = collision_circle | ||
+ | r = p.collision_rect | ||
+ | |||
+ | if circle_rect_collide? | ||
+ | if c.center.y < top(r) | ||
+ | self.position = {position.x, | ||
+ | @velocity.y *= -1 | ||
+ | elsif c.center.y > bottom(r) | ||
+ | self.position = {position.x, | ||
+ | @velocity.y *= -1 | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | c = collision_circle | ||
+ | if c.center.y - c.radius < 0 | ||
+ | @velocity.y = +@velocity.y.abs | ||
+ | end | ||
+ | if c.center.y + c.radius > GAME_HEIGHT | ||
+ | @velocity.y = -@velocity.y.abs | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def collision_circle : Circle | ||
+ | x = position.x - @shape.origin.x + @shape.radius | ||
+ | y = position.y - @shape.origin.y + @shape.radius | ||
+ | Circle.new(SF.vector2f(x, | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def process_events(window : SF::Window) | ||
+ | while event = window.poll_event | ||
+ | if event.is_a? SF:: | ||
+ | window.close | ||
+ | end | ||
+ | |||
+ | if event.is_a? SF:: | ||
+ | if event.code == SF:: | ||
+ | window.close | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def setup_paddles : Array(Paddle) | ||
+ | paddles = [] of Paddle | ||
+ | paddles << Paddle.new( | ||
+ | SF.vector2f(40, | ||
+ | SF.vector2f(20, | ||
+ | SF:: | ||
+ | PADDLE_SPEED, | ||
+ | {" | ||
+ | ) | ||
+ | |||
+ | paddles << Paddle.new( | ||
+ | SF.vector2f(GAME_WIDTH - 40, GAME_HEIGHT / 2), | ||
+ | SF.vector2f(20, | ||
+ | SF:: | ||
+ | PADDLE_SPEED, | ||
+ | {" | ||
+ | ) | ||
+ | |||
+ | paddles | ||
+ | end | ||
+ | |||
+ | def setupo_balls : Array(Ball) | ||
+ | balls = [] of Ball | ||
+ | n = 100 | ||
+ | |||
+ | n.times do |i| | ||
+ | sx = rand(0.5 .. 3.0) | ||
+ | sy = rand(0.5 .. 3.0) | ||
+ | balls << Ball.new( | ||
+ | SF.vector2f(GAME_WIDTH / n * (i + 1), GAME_HEIGHT / 2), | ||
+ | 15.0, | ||
+ | SF:: | ||
+ | (255 - (255 / n * (i + 1))).to_i, | ||
+ | 128), | ||
+ | SF.vector2f(BALL_SPEED * sx, BALL_SPEED * sy) | ||
+ | ) | ||
+ | end | ||
+ | |||
+ | balls | ||
+ | end | ||
+ | |||
+ | ###################################################################### | ||
+ | |||
+ | window = SF:: | ||
+ | SF:: | ||
+ | ) | ||
+ | |||
+ | paddles = setup_paddles | ||
+ | balls = setupo_balls | ||
+ | |||
+ | clock = SF:: | ||
+ | elapsed_time = SF:: | ||
+ | |||
+ | while window.open? | ||
+ | # process events and players' | ||
+ | process_events window | ||
+ | paddles.each { |p| p.process_input } | ||
+ | |||
+ | # update | ||
+ | paddles.each { |p| p.update elapsed_time } | ||
+ | balls.each { |b| b.update elapsed_time, | ||
+ | |||
+ | # render | ||
+ | window.clear | ||
+ | paddles.each { |p| window.draw p } | ||
+ | balls.each { |b| window.draw b } | ||
+ | window.display | ||
+ | |||
+ | elapsed_time = clock.restart | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | ===== src/ | ||
+ | |||
+ | |||
+ | <file crystal> | ||
+ | require " | ||
+ | |||
+ | def left(r : SF:: | ||
+ | r.left | ||
+ | end | ||
+ | |||
+ | def right(r : SF:: | ||
+ | r.left + r.width | ||
+ | end | ||
+ | |||
+ | def top(r : SF:: | ||
+ | r.top | ||
+ | end | ||
+ | |||
+ | def bottom(r : SF:: | ||
+ | r.top + r.height | ||
+ | end | ||
+ | |||
+ | struct Circle | ||
+ | property center : SF:: | ||
+ | property radius : Float32 | ||
+ | |||
+ | def initialize(@center, | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def circle_rect_collide? | ||
+ | c = circle.center | ||
+ | |||
+ | t = c | ||
+ | t.x = left(rect) if c.x < left(rect) | ||
+ | t.x = right(rect) if c.x > right(rect) | ||
+ | t.y = top(rect) if c.y < top(rect) | ||
+ | t.y = bottom(rect) if c.y > bottom(rect) | ||
+ | |||
+ | ct = t - c | ||
+ | distance2 = ct.x ** 2 + ct.y ** 2 | ||
+ | radius2 = circle.radius ** 2 | ||
+ | |||
+ | distance2 < radius2 | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | ===== shard.yml ===== | ||
+ | |||
+ | |||
+ | <file yaml> | ||
+ | name: crsfml-pong-take-5 | ||
+ | version: 0.1.0 | ||
+ | |||
+ | authors: | ||
+ | - watercat < | ||
+ | |||
+ | targets: | ||
+ | crsfml-pong-take-5: | ||
+ | main: src/ | ||
+ | |||
+ | crystal: 1.7.3 | ||
+ | |||
+ | license: WTFPL | ||
+ | |||
+ | dependencies: | ||
+ | crsfml: | ||
+ | github: oprypin/ | ||
+ | version: ~> 2.5.2 | ||
+ | </ | ||