summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--assets/.none0
-rw-r--r--main.rb224
2 files changed, 224 insertions, 0 deletions
diff --git a/assets/.none b/assets/.none
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/assets/.none
diff --git a/main.rb b/main.rb
new file mode 100644
index 0000000..2372842
--- /dev/null
+++ b/main.rb
@@ -0,0 +1,224 @@
+WindowWidth = 800
+WindowHeight = 600
+WindowTitle = 'Almost Ping Pong'
+Rl.init_window(WindowWidth, WindowHeight, WindowTitle)
+$frames = 0 # number of frames elapsed
+$points = 0 # number of times a paddle was hit
+$best_points = 0
+$dead = false
+$world_rec = Rl::Rectangle.new(0, 0, WindowWidth, WindowHeight)
+include FECS
+
+Cmp.new('Box', :obj)
+Cmp.new('Position', :x, :y)
+Cmp.new('Velocity', :x, :y)
+Cmp.new('Paddle', :side)
+Cmp.new('Ball')
+Cmp.new('Color', :obj)
+Cmp.new('EaseToward', :start, :finish, :time)
+
+Ent.new(
+ Cmp::Paddle.new(side: 'left'),
+ Cmp::Box.new(obj: Rl::Rectangle.new(0,0,25,100)),
+ Cmp::Position.new(x: 35, y: WindowHeight / 2),
+ Cmp::Color.new(obj: Rl::Color.white)
+)
+
+Ent.new(
+ Cmp::Paddle.new(side: 'right'),
+ Cmp::Box.new(obj: Rl::Rectangle.new(0,0,25,100)),
+ Cmp::Position.new(x: WindowWidth - 35, y: WindowHeight / 2),
+ Cmp::Color.new(obj: Rl::Color.white)
+)
+
+Ent.new(
+ Cmp::Ball.new,
+ Cmp::Box.new(obj: Rl::Rectangle.new(0,0,25,25)),
+ Cmp::Position.new(x: WindowWidth/2, y: WindowHeight/2),
+ Cmp::Velocity.new(x: 2, y: 0),
+ Cmp::Color.new(obj: Rl::Color.fire_brick)
+)
+
+def ease(start:, finish:, time:)
+ distance = finish - start
+ ((1 - (1 - time)**3) * distance) + start
+end
+
+
+Scn.new('Main')
+
+# add all systems to a scene when they are created
+Scn::Main.add(
+ Sys.new('Input') do
+ unless $dead
+ if Rl.key_pressed? 32 # spacebar
+ Scn::Main.add Sys::Move, Sys::Gravity
+ Cmp::Ball.first.entity.component[Cmp::Velocity].y -= 4
+ end
+ end
+ if Rl.key_pressed? 82
+ $dead = false
+ $points = 0
+ Scn::Main.remove Sys::Move, Sys::Gravity
+ ball = Cmp::Ball.first.entity
+
+ # make ball go right when starting
+ ball.component[Cmp::Velocity].x = ball.component[Cmp::Velocity].x.abs
+ # reset gravity
+ ball.component[Cmp::Velocity].y = 0
+
+ # move to center
+ ball.component[Cmp::Position].x = WindowWidth/2
+ ball.component[Cmp::Position].y = WindowHeight/2
+
+ # slide paddles to center
+ Ent.group(Cmp::Paddle, Cmp::Position) do |paddle, position, entity|
+ if !entity.components[Cmp::EaseToward].nil?
+ entity.component[Cmp::EaseToward].delete
+ end
+ entity.add Cmp::EaseToward.new(start: position.y, finish: WindowHeight/2, time: 0)
+ end
+ end
+ end,
+
+ Sys.new('Gravity') do
+ velocity = Cmp::Ball.first.entity.component[Cmp::Velocity]
+ unless velocity.y > 15
+ velocity.y += (1.0/6.0)
+ end
+ end,
+
+ # moving a paddle to new position
+ Sys.new('EaseToward') do
+ Ent.group(Cmp::EaseToward, Cmp::Position) do |ease, position, entity|
+ ease.time += Rl.frame_time * 2
+ if ease.time > 1
+ position.y = ease.finish
+ ease.delete
+ else
+ position.y = ease(start: ease.start, finish: ease.finish, time: ease.time)
+ end
+ end
+ end,
+
+ Sys.new('Move') do
+ ball_position = Cmp::Ball.first.entity.component[Cmp::Position]
+ ball_velocity = Cmp::Ball.first.entity.component[Cmp::Velocity]
+ ball_box = Cmp::Ball.first.entity.component[Cmp::Box]
+
+ # center the box
+ ball_box.obj.x = ball_position.x - (ball_box.obj.w/2)
+ ball_box.obj.y = ball_position.y - (ball_box.obj.h/2)
+
+ # used for checking if where the ball will be next frame
+ future_ball = Rl::Rectangle.new(ball_box.obj.x + ball_velocity.x,
+ ball_box.obj.y + ball_velocity.y,
+ ball_box.obj.w,
+ ball_box.obj.h)
+
+ # used for checking if we are colliding a paddle directly from above/below
+ future_ball_side = Rl::Rectangle.new(ball_box.obj.x,
+ ball_box.obj.y + ball_velocity.y,
+ ball_box.obj.w,
+ ball_box.obj.h)
+
+ # check if possible to move, bounce off else
+ # iterate over all paddles that have a position and a box
+ Ent.group(Cmp::Paddle, Cmp::Position, Cmp::Box) do |paddle, paddle_position, paddle_box|
+
+ # center the box
+ paddle_box.obj.x = paddle_position.x - (paddle_box.obj.w/2)
+ paddle_box.obj.y = paddle_position.y - (paddle_box.obj.h/2)
+
+ if future_ball.collide_with_rec? paddle_box.obj
+ if future_ball_side.collide_with_rec? paddle_box.obj
+ # if it is colliding from above/below then dont bounce back
+ # and set horizontal speed to 0
+ ball_velocity.y = 0
+ else
+ if paddle.side == 'right'
+ unless ball_velocity.x < 0
+ opposite = Cmp::Paddle.find { |pad| pad.side == 'left' }.entity
+ opposite_position = opposite.component[Cmp::Position]
+ opposite.add Cmp::EaseToward.new(start: opposite_position.y, finish: (60..(WindowHeight-60)).to_a.sample, time: 0)
+ ball_velocity.x = -ball_velocity.x.abs
+ $points += 1
+ end
+ else
+ unless ball_velocity.x > 0
+ opposite = Cmp::Paddle.find { |pad| pad.side == 'right' }.entity
+ opposite_position = opposite.component[Cmp::Position]
+ opposite.add Cmp::EaseToward.new(start: opposite_position.y, finish: (60..(WindowHeight-60)).to_a.sample, time: 0)
+ ball_velocity.x = ball_velocity.x.abs
+ $points += 1
+ end
+ end
+ end
+ end
+ ball_position.x += ball_velocity.x
+ ball_position.y += ball_velocity.y
+ end
+ end,
+
+ Sys.new('CheckDeath') do
+ # if ball outside of screen
+ ball_position = Cmp::Ball.first.entity.component[Cmp::Position]
+ ball_box = Cmp::Ball.first.entity.component[Cmp::Box]
+ ball_box.obj.x = ball_position.x - (ball_box.obj.w/2)
+ ball_box.obj.y = ball_position.y - (ball_box.obj.h/2)
+
+ unless ball_box.obj.collide_with_rec? $world_rec
+ Scn::Main.remove(Sys::Move)
+ $dead = true
+ if $points > $best_points
+ $best_points = $points
+ end
+ end
+
+ end,
+
+ Sys.new('Render') do
+ Ent.group(Cmp::Paddle, Cmp::Position, Cmp::Box, Cmp::Color) do |paddle, position, box, color|
+ box.obj.x = position.x - (box.obj.w/2)
+ box.obj.y = position.y - (box.obj.h/2)
+ puts box.obj
+ box.obj.draw(color: color.obj)
+ end
+ Ent.group(Cmp::Ball, Cmp::Position, Cmp::Box, Cmp::Color) do |paddle, position, box, color|
+ box.obj.x = position.x - (box.obj.w/2)
+ box.obj.y = position.y - (box.obj.h/2)
+ box.obj.draw(color: color.obj)
+ end
+ "Points: #{$points}".draw(color: Rl::Color.dodger_blue, font_size: 48, x: 10, y: 10)
+ if $dead
+ "The Ball is Lost".draw(color: Rl::Color.fire_brick, font_size: 65, x: 130, y: 150)
+ "Press R to try again".draw(color: Rl::Color.fire_brick, font_size: 30, x: 205, y: 270)
+ "Best Score: #{$best_points}".draw(color: Rl::Color.fire_brick, font_size: 30, x: 205, y: 270 + 50)
+ end
+ end,
+
+ Sys.new('IncrementFrame') do
+ $frames += 1
+ end,
+)
+
+Scn::Main.remove(Sys::Move, Sys::Gravity) # dont begin moving at the start
+
+# define order systems should be executed in
+Order.sort(
+ Sys::Input,
+ Sys::Gravity,
+ Sys::EaseToward,
+ Sys::Move,
+ Sys::CheckDeath,
+ Sys::Render,
+ Sys::IncrementFrame
+)
+
+Rl.target_fps = 60
+Rl.while_window_open do
+ Rl.draw(clear_color: Rl::Color.black) do
+ Scn::Main.call # execute the main scene once per frame
+ end
+end
+