Skip to content

Commit

Permalink
Flappy bird multiplayer. (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix authored Jun 24, 2024
1 parent 8157699 commit 49123e5
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 32 deletions.
142 changes: 130 additions & 12 deletions examples/flappy-bird/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Copyright, 2024, by Samuel Williams.

require_relative 'highscore'
require 'async/variable'

WIDTH = 420
HEIGHT = 640
Expand Down Expand Up @@ -62,11 +63,13 @@ def jump
@velocity = 300.0
end

def render(builder)
def render(builder, remote: false)
rotation = (@velocity / 20.0).clamp(-40.0, 40.0)
rotate = "rotate(#{-rotation}deg)";

builder.inline_tag(:div, class: 'bird', style: "left: #{@x}px; bottom: #{@y}px; width: #{@width}px; height: #{@height}px; transform: #{rotate};")
class_name = remote ? 'bird remote' : 'bird'

builder.inline_tag(:div, class: class_name, style: "left: #{@x}px; bottom: #{@y}px; width: #{@width}px; height: #{@height}px; transform: #{rotate};")
end
end

Expand Down Expand Up @@ -160,8 +163,10 @@ def render(builder)
end

class FlappyBirdView < Live::View
def initialize(...)
super
def initialize(*arguments, multiplayer_state: nil, **options)
super(*arguments, **options)

@multiplayer_state = multiplayer_state

@game = nil
@bird = nil
Expand All @@ -173,6 +178,15 @@ def initialize(...)
@prompt = "Press Space to Start"

@random = nil
@dead = nil
end

attr :bird

def bind(page)
super

@multiplayer_state.add_player(self)
end

def close
Expand All @@ -181,15 +195,15 @@ def close
@game = nil
end

@multiplayer_state.remove_player(self)

super
end

def handle(event)
case event[:type]
when "keypress"
if @game.nil?
start_game!
elsif event.dig(:detail, :key) == " "
if event.dig(:detail, :key) == " "
play_sound("quack") if rand > 0.5

@bird&.jump
Expand All @@ -202,12 +216,13 @@ def forward_keypress
end

def reset!
@dead = Async::Variable.new
@random = Random.new(1)

@bird = Bird.new
@pipes = [
Pipe.new(WIDTH * 1/2, HEIGHT/2, random: @random),
Pipe.new(WIDTH * 2/2, HEIGHT/2, random: @random)
Pipe.new(WIDTH + WIDTH * 1/2, HEIGHT/2, random: @random),
Pipe.new(WIDTH + WIDTH * 2/2, HEIGHT/2, random: @random)
]
@bonus = nil
@score = 0
Expand Down Expand Up @@ -247,19 +262,27 @@ def stop_music
end

def game_over!
Console.info(self, "Player has died.")
@dead.resolve(true)

play_sound("death")
stop_music

Highscore.create!(ENV.fetch("PLAYER", "Anonymous"), @score)

@prompt = "Game Over! Score: #{@score}. Press Space to Restart"
@prompt = "Game Over! Score: #{@score}."
@game = nil

self.update!

raise Async::Stop
end

def preparing(message)
@prompt = message
self.update!
end

def start_game!
if @game
@game.stop
Expand All @@ -272,6 +295,10 @@ def start_game!
@game = self.run!
end

def wait_until_dead
@dead.wait
end

def step(dt)
@bird.step(dt)
@pipes.each do |pipe|
Expand Down Expand Up @@ -310,7 +337,7 @@ def step(dt)
end
end

def run!(dt = 1.0/20.0)
def run!(dt = 1.0/10.0)
Async do
start_time = Async::Clock.now

Expand Down Expand Up @@ -357,8 +384,99 @@ def render(builder)
end

@bonus&.render(builder)

@multiplayer_state&.players&.each do |player|
if player != self
player.bird&.render(builder, remote: true)
end
end
end
end
end

Application = Lively::Application[FlappyBirdView]
class Resolver < Live::Resolver
def initialize(**state)
super()

@state = state
end

def call(id, data)
if klass = @allowed[data[:class]]
return klass.new(id, **data, **@state)
end
end
end

class MultiplayerState
MINIMUM_PLAYERS = 1
GAME_START_TIMEOUT = 5

def initialize
@joined = Set.new
@players = nil

@player_joined = Async::Condition.new

@game = self.run!
end

attr :players

def run!
Async do
while true
Console.info(self, "Waiting for players...")
while @joined.size < MINIMUM_PLAYERS
@player_joined.wait
end

Console.info(self, "Starting game...")
GAME_START_TIMEOUT.downto(0).each do |i|
@joined.each do |player|
player.preparing("Starting game in #{i}...")
end
sleep 1
end

@players = @joined.to_a
Console.info(self, "Game started with #{@players.size} players")

@players.each do |player|
player.start_game!
end

@players.each do |player|
player.wait_until_dead
end

Console.info(self, "Game over")
@players = nil
end
end
end

def add_player(player)
# Console.info(self, "Adding player: #{player}")
@joined << player
player.preparing("Waiting for other players...")
@player_joined.signal
end

def remove_player(player)
# Console.info(self, "Removing player: #{player}")
@joined.delete(player)
end
end

class Application < Lively::Application
def self.resolver
Resolver.new(multiplayer_state: MultiplayerState.new).tap do |resolver|
resolver.allow(FlappyBirdView)
end
end

def body(...)
FlappyBirdView.new(...)
end
end
26 changes: 12 additions & 14 deletions examples/flappy-bird/gems.locked
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,20 @@ PATH
GEM
remote: https://rubygems.org/
specs:
async (2.11.0)
async (2.12.0)
console (~> 1.25, >= 1.25.2)
fiber-annotation
io-event (~> 1.5, >= 1.5.1)
timers (~> 4.1)
io-event (~> 1.6)
async-container (0.18.2)
async (~> 2.10)
async-http (0.66.3)
async-http (0.67.1)
async (>= 2.10.2)
async-pool (>= 0.6.1)
io-endpoint (~> 0.10, >= 0.10.3)
io-stream (~> 0.4)
protocol-http (~> 0.26.0)
protocol-http1 (~> 0.19.0)
protocol-http2 (~> 0.17.0)
protocol-http2 (~> 0.18.0)
traces (>= 0.10.0)
async-http-cache (0.4.3)
async-http (~> 0.56)
Expand Down Expand Up @@ -55,9 +54,9 @@ GEM
fiber-annotation (0.2.0)
fiber-local (1.1.0)
fiber-storage
fiber-storage (0.1.0)
fiber-storage (0.1.1)
io-endpoint (0.10.3)
io-event (1.5.1)
io-event (1.6.4)
io-stream (0.4.0)
json (2.7.2)
live (0.11.0)
Expand All @@ -73,21 +72,20 @@ GEM
protocol-http (0.26.5)
protocol-http1 (0.19.1)
protocol-http (~> 0.22)
protocol-http2 (0.17.0)
protocol-http2 (0.18.0)
protocol-hpack (~> 1.4)
protocol-http (~> 0.18)
protocol-rack (0.5.1)
protocol-http (~> 0.23)
rack (>= 1.0)
protocol-websocket (0.12.1)
protocol-websocket (0.13.0)
protocol-http (~> 0.2)
rack (3.0.11)
rack (3.1.3)
samovar (2.3.0)
console (~> 1.0)
mapping (~> 1.0)
sqlite3 (2.0.1-arm64-darwin)
sqlite3 (2.0.1-x86_64-linux-gnu)
timers (4.3.5)
sqlite3 (2.0.2-arm64-darwin)
sqlite3 (2.0.2-x86_64-linux-gnu)
traces (0.11.1)
xrb (0.6.1)

Expand All @@ -100,4 +98,4 @@ DEPENDENCIES
sqlite3

BUNDLED WITH
2.5.5
2.5.9
16 changes: 13 additions & 3 deletions examples/flappy-bird/public/_static/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ body {

position: relative;
overflow: hidden;

transform: translate3d(0,0,0);
}

.flappy .score {
Expand Down Expand Up @@ -50,7 +52,13 @@ body {
position: absolute;
background-size: contain;

transition: all 0.05s linear 0s;
transform: translate3d(0,0,0);
transition: all 0.1s linear 0s;
}

.flappy .bird.remote {
opacity: 50%;
filter: grayscale(100%);
}

.flappy .pipe {
Expand All @@ -59,7 +67,8 @@ body {
position: absolute;
background-size: contain;

transition: all 0.05s linear 0s;
transform: translate3d(0,0,0);
transition: all 0.1s linear 0s;
}

.flappy .gemstone {
Expand All @@ -68,5 +77,6 @@ body {
position: absolute;
background-size: contain;

transition: all 0.05s linear 0s;
transform: translate3d(0,0,0);
transition: all 0.1s linear 0s;
}
2 changes: 1 addition & 1 deletion examples/worms/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def handle(event)
end

def forward_keypress
"live.forwardEvent(#{JSON.dump(@id)}, event, {value: event.target.value, key: event.key})"
"live.forwardEvent(#{JSON.dump(@id)}, event, {key: event.key})"
end

def render(builder)
Expand Down
8 changes: 6 additions & 2 deletions lib/lively/environment/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ module Environment
module Application
include Falcon::Environment::Server

def url
"http://localhost:9292"
# def url
# "http://localhost:9292"
# end

def count
1
end

def application
Expand Down

0 comments on commit 49123e5

Please sign in to comment.