class PirateGame::ClientApp

Public Class Methods

run() click to toggle source
# File lib/pirate_game/client_app.rb, line 3
def self.run
  @my_app = Shoes.app width: 360, height: 360, resizeable: false, title: 'Pirate Game' do

    require 'pirate_game/shoes4_patch'

    def animate fps, &block
      opts = { framerate: fps }
      PirateGame::Animation.new @app, opts, block
    end

    ##
    # Creates the animation trigger for animating items.  An animatable item
    # must respond to #animate and accept a frame number.

    def animate_items
      @items_animation = animate(30) do |frame|
        @background.animate frame
      end
    end

    ##
    # Creates the waves and ship graphics that must be animated.

    def create_items
      @background = PirateGame::Background.new(self)
    end

    ##
    # Clears the app, draws the background, ship and waves, then yields to
    # draw UI items.

    def draw_items
      clear

      @background.draw do
        yield
      end
    end

    ##
    # Sets the application state

    def state= state
      @state = state
      @client.set_state @state
    end

    ##
    # The launch screen.

    def launch_screen
      @items_animation.start if @items_animation

      pirate_ship do
        title "What's your name", stroke: PirateGame::Boot::COLORS[:dark]

        edit_line text: 'Name' do |s|
          @name = s.text
        end

        button('launch') {
          @client = PirateGame::Client.new(name: @name)
        }
      end

      @state_watcher = animate(5) {
        watch_state
      }
    end

    ##
    # Draws a pirate ship background with waves yields to draw additional
    # UI.

    def pirate_ship
      draw_items do
        stack margin: 20 do
          yield
        end
      end
    end

    ##
    # Watches the state of the client to switch to a new screen.

    def watch_state
      return if @client.nil?
      return if @state == @client.state

      @state = @client.state

      case @state
      when :select_game
        select_game_screen
      when :pub
        pub_screen
      when :stage
        stage_screen
      when :end
        end_screen
      end
    end

    ##
    # Displays the UI for choosing a game to join

    def select_game_screen
      @items_animation.start if @items_animation

      motherships = @client.find_all_motherships

      title_text = if motherships.empty? then
                     "No Games Found"
                   else
                     "Choose Game"
                   end

      pirate_ship do
        title title_text, stroke: PirateGame::Boot::COLORS[:dark]

        for mothership in motherships
          draw_mothership_button mothership
        end

        button('rescan') {
          select_game_screen
        }
      end
    rescue DRb::DRbConnError
      state = :select_game
      select_game_screen
    end

    ##
    # The pirate pub screen where you wait to start a game

    def pub_screen
      @stage_animation.remove if @stage_animation
      @items_animation.stop if @items_animation

      @pub_tagline ||= "Welcome #{@client.name}"

      clear do
        background PirateGame::Boot::COLORS[:pub]
        stack :margin => 20 do
          title "Pirate Pub", stroke: PirateGame::Boot::COLORS[:light]
          tagline @pub_tagline, stroke: PirateGame::Boot::COLORS[:light]

          stack do @status = para '', stroke: PirateGame::Boot::COLORS[:light] end

          @registered = nil
          @updating_area = stack
          stack do
            @chat_title = tagline 'Pub Chat', stroke: PirateGame::Boot::COLORS[:light]
            @chat_input = flow
            @chat_messages = stack
          end
        end

        # checks for registration changes
        # updates chat messages
        @pub_animation = animate(5) {
          if @client

            # updates screen only when registration state changes
            update_on_registration_change

            # updates screen, runs every time
            update_chat_room
          end
        }
      end
    rescue DRb::DRbConnError
      state = :select_game
      select_game_screen
    end

    ##
    # The screen where the game occurs

    def stage_screen
      @pub_animation.remove if @pub_animation
      @items_animation.start if @items_animation

      # if we get back to pub then stage was success
      @pub_tagline = 'SUCCESS!'

      pirate_ship do
        title PirateCommand.exclaim!, stroke: PirateGame::Boot::COLORS[:dark]

        @instruction = caption stroke: PirateGame::Boot::COLORS[:dark]
        @progress = progress

        @client.bridge.items.each_slice(3).with_index do |items, row|
          items.each_with_index do |item, column|
            bridge_button =
              PirateGame::BridgeButton.new self, item, row, column do
                @client.clicked item
              end

            @background.add_extra_item bridge_button
          end
        end
      end

      @stage_animation = animate(10) {
        @client.issue_command unless @client.waiting?

        @instruction.replace @client.current_action

        progress_fraction = (@client.action_time_left.to_f / @client.completion_time.to_f)
        @progress.fraction = progress_fraction
      }
    rescue DRb::DRbConnError
      state = :select_game
      select_game_screen
    end

    ##
    # The end-game screen

    def end_screen
      @pub_animation.remove if @pub_animation
      @stage_animation.remove if @stage_animation
      @items_animation.stop if @items_animation

      clear do
        jolly_roger = File.expand_path '../../../imgs/jolly_roger_sm.png', __FILE__
        background PirateGame::Boot::COLORS[:dark]
        background jolly_roger, height: 256
        background rgb(0, 0, 0, 180)

        stack margin: 20 do

          title "END OF GAME", stroke: PirateGame::Boot::COLORS[:light]

          if @client.slop_bucket[:end_game]
            game_stats = @client.slop_bucket[:end_game]
            para "Game Stats", stroke: PirateGame::Boot::COLORS[:light]
            para "Total Stages Completed: #{game_stats[:total_stages]}", stroke: PirateGame::Boot::COLORS[:light]
            para "Total Actions: #{game_stats[:total_actions]}", stroke: PirateGame::Boot::COLORS[:light]
            para "My Contribution: #{game_stats[:player_breakdown][DRb.uri]}", stroke: PirateGame::Boot::COLORS[:light]
          end
        end
      end
    rescue DRb::DRbConnError
      state = :select_game
      select_game_screen
    end

    ##
    # If the registration state has changed, yields to the block.

    def detect_registration_change
      return if @client.registered? == @registered

      @registered = @client.registered?

      @status.replace "#{"Not " unless @registered}Registered"

      yield
    end

    ##
    # Updates the chat messages with new messages

    def update_chat_room
      if @registered
        @chat_messages.clear do
          for msg, name in @client.log_book
            para "#{name} said: #{msg}", stroke: PirateGame::Boot::COLORS[:light]
          end
        end
      end
    end

    ##
    # Updates the registration view in the pub screen

    def update_on_registration_change
      detect_registration_change do
        @updating_area.clear do
          button("Register") { register } unless @registered
        end

        # chat input box only appears when registered
        @chat_input.clear do
          if @registered
            el = edit_line

            button("Send") {
              unless el.text.empty?
                @client.broadcast(el.text)
                el.text = ''
              end
            }
          end
        end
      end
    end

    ##
    # Draws a button for joining a game playing on +mothership+

    def draw_mothership_button mothership
      button(mothership[:name]) {|b|
        begin
          @client.initiate_communication_with_mothership(b.text)
          @client.register
        rescue
          select_game_screen
        end
      }
    end

    ##
    # Registers the client with a game master

    def register
      @client.register if @client
    end

    ##
    # Unregisters a game with a game master

    def unregister
      @client.unregister if @client
    end

    @client = nil
    create_items
    animate_items
    launch_screen
  end
ensure
  @my_app.unregister if @my_app
end

Public Instance Methods

animate(fps, &block) click to toggle source
# File lib/pirate_game/client_app.rb, line 8
def animate fps, &block
  opts = { framerate: fps }
  PirateGame::Animation.new @app, opts, block
end
animate_items() click to toggle source

Creates the animation trigger for animating items. An animatable item must respond to animate and accept a frame number.

# File lib/pirate_game/client_app.rb, line 17
def animate_items
  @items_animation = animate(30) do |frame|
    @background.animate frame
  end
end
create_items() click to toggle source

Creates the waves and ship graphics that must be animated.

# File lib/pirate_game/client_app.rb, line 26
def create_items
  @background = PirateGame::Background.new(self)
end
detect_registration_change() { || ... } click to toggle source

If the registration state has changed, yields to the block.

# File lib/pirate_game/client_app.rb, line 256
def detect_registration_change
  return if @client.registered? == @registered

  @registered = @client.registered?

  @status.replace "#{"Not " unless @registered}Registered"

  yield
end
draw_items() { || ... } click to toggle source

Clears the app, draws the background, ship and waves, then yields to draw UI items.

# File lib/pirate_game/client_app.rb, line 34
def draw_items
  clear

  @background.draw do
    yield
  end
end
draw_mothership_button(mothership) click to toggle source

Draws a button for joining a game playing on mothership

# File lib/pirate_game/client_app.rb, line 307
def draw_mothership_button mothership
  button(mothership[:name]) {|b|
    begin
      @client.initiate_communication_with_mothership(b.text)
      @client.register
    rescue
      select_game_screen
    end
  }
end
end_screen() click to toggle source

The end-game screen

# File lib/pirate_game/client_app.rb, line 224
def end_screen
  @pub_animation.remove if @pub_animation
  @stage_animation.remove if @stage_animation
  @items_animation.stop if @items_animation

  clear do
    jolly_roger = File.expand_path '../../../imgs/jolly_roger_sm.png', __FILE__
    background PirateGame::Boot::COLORS[:dark]
    background jolly_roger, height: 256
    background rgb(0, 0, 0, 180)

    stack margin: 20 do

      title "END OF GAME", stroke: PirateGame::Boot::COLORS[:light]

      if @client.slop_bucket[:end_game]
        game_stats = @client.slop_bucket[:end_game]
        para "Game Stats", stroke: PirateGame::Boot::COLORS[:light]
        para "Total Stages Completed: #{game_stats[:total_stages]}", stroke: PirateGame::Boot::COLORS[:light]
        para "Total Actions: #{game_stats[:total_actions]}", stroke: PirateGame::Boot::COLORS[:light]
        para "My Contribution: #{game_stats[:player_breakdown][DRb.uri]}", stroke: PirateGame::Boot::COLORS[:light]
      end
    end
  end
rescue DRb::DRbConnError
  state = :select_game
  select_game_screen
end
launch_screen() click to toggle source

The launch screen.

# File lib/pirate_game/client_app.rb, line 53
def launch_screen
  @items_animation.start if @items_animation

  pirate_ship do
    title "What's your name", stroke: PirateGame::Boot::COLORS[:dark]

    edit_line text: 'Name' do |s|
      @name = s.text
    end

    button('launch') {
      @client = PirateGame::Client.new(name: @name)
    }
  end

  @state_watcher = animate(5) {
    watch_state
  }
end
pirate_ship() { || ... } click to toggle source

Draws a pirate ship background with waves yields to draw additional UI.

# File lib/pirate_game/client_app.rb, line 77
def pirate_ship
  draw_items do
    stack margin: 20 do
      yield
    end
  end
end
pub_screen() click to toggle source

The pirate pub screen where you wait to start a game

# File lib/pirate_game/client_app.rb, line 139
def pub_screen
  @stage_animation.remove if @stage_animation
  @items_animation.stop if @items_animation

  @pub_tagline ||= "Welcome #{@client.name}"

  clear do
    background PirateGame::Boot::COLORS[:pub]
    stack :margin => 20 do
      title "Pirate Pub", stroke: PirateGame::Boot::COLORS[:light]
      tagline @pub_tagline, stroke: PirateGame::Boot::COLORS[:light]

      stack do @status = para '', stroke: PirateGame::Boot::COLORS[:light] end

      @registered = nil
      @updating_area = stack
      stack do
        @chat_title = tagline 'Pub Chat', stroke: PirateGame::Boot::COLORS[:light]
        @chat_input = flow
        @chat_messages = stack
      end
    end

    # checks for registration changes
    # updates chat messages
    @pub_animation = animate(5) {
      if @client

        # updates screen only when registration state changes
        update_on_registration_change

        # updates screen, runs every time
        update_chat_room
      end
    }
  end
rescue DRb::DRbConnError
  state = :select_game
  select_game_screen
end
register() click to toggle source

Registers the client with a game master

# File lib/pirate_game/client_app.rb, line 321
def register
  @client.register if @client
end
select_game_screen() click to toggle source

Displays the UI for choosing a game to join

# File lib/pirate_game/client_app.rb, line 109
def select_game_screen
  @items_animation.start if @items_animation

  motherships = @client.find_all_motherships

  title_text = if motherships.empty? then
                 "No Games Found"
               else
                 "Choose Game"
               end

  pirate_ship do
    title title_text, stroke: PirateGame::Boot::COLORS[:dark]

    for mothership in motherships
      draw_mothership_button mothership
    end

    button('rescan') {
      select_game_screen
    }
  end
rescue DRb::DRbConnError
  state = :select_game
  select_game_screen
end
stage_screen() click to toggle source

The screen where the game occurs

# File lib/pirate_game/client_app.rb, line 183
def stage_screen
  @pub_animation.remove if @pub_animation
  @items_animation.start if @items_animation

  # if we get back to pub then stage was success
  @pub_tagline = 'SUCCESS!'

  pirate_ship do
    title PirateCommand.exclaim!, stroke: PirateGame::Boot::COLORS[:dark]

    @instruction = caption stroke: PirateGame::Boot::COLORS[:dark]
    @progress = progress

    @client.bridge.items.each_slice(3).with_index do |items, row|
      items.each_with_index do |item, column|
        bridge_button =
          PirateGame::BridgeButton.new self, item, row, column do
            @client.clicked item
          end

        @background.add_extra_item bridge_button
      end
    end
  end

  @stage_animation = animate(10) {
    @client.issue_command unless @client.waiting?

    @instruction.replace @client.current_action

    progress_fraction = (@client.action_time_left.to_f / @client.completion_time.to_f)
    @progress.fraction = progress_fraction
  }
rescue DRb::DRbConnError
  state = :select_game
  select_game_screen
end
state=(state) click to toggle source

Sets the application state

# File lib/pirate_game/client_app.rb, line 45
def state= state
  @state = state
  @client.set_state @state
end
unregister() click to toggle source

Unregisters a game with a game master

# File lib/pirate_game/client_app.rb, line 328
def unregister
  @client.unregister if @client
end
update_chat_room() click to toggle source

Updates the chat messages with new messages

# File lib/pirate_game/client_app.rb, line 269
def update_chat_room
  if @registered
    @chat_messages.clear do
      for msg, name in @client.log_book
        para "#{name} said: #{msg}", stroke: PirateGame::Boot::COLORS[:light]
      end
    end
  end
end
update_on_registration_change() click to toggle source

Updates the registration view in the pub screen

# File lib/pirate_game/client_app.rb, line 282
def update_on_registration_change
  detect_registration_change do
    @updating_area.clear do
      button("Register") { register } unless @registered
    end

    # chat input box only appears when registered
    @chat_input.clear do
      if @registered
        el = edit_line

        button("Send") {
          unless el.text.empty?
            @client.broadcast(el.text)
            el.text = ''
          end
        }
      end
    end
  end
end
watch_state() click to toggle source

Watches the state of the client to switch to a new screen.

# File lib/pirate_game/client_app.rb, line 88
def watch_state
  return if @client.nil?
  return if @state == @client.state

  @state = @client.state

  case @state
  when :select_game
    select_game_screen
  when :pub
    pub_screen
  when :stage
    stage_screen
  when :end
    end_screen
  end
end