yeah 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e63e1abe8491c77fbd17d9ae4b040bf8349afba3
4
- data.tar.gz: d4d7d868f5f130a4bf1949d5b3eedc4b4a84f329
3
+ metadata.gz: 17da100f4d2feff2cb2eefb5f5f779d56404f044
4
+ data.tar.gz: ff877fec7e0cab390ebf0419e4aaf74dc93ae415
5
5
  SHA512:
6
- metadata.gz: d77b196bb0caf20f8f5a95ff68c8cbe001508dbab5c138dbc7e3eab6cc3dac345bf2fc863203ea9873189a9c97ad98a66e4f0d31d6608520a28d14403b686569
7
- data.tar.gz: d66c9ff09bf63fd247d22d1cf83866ea54aec9ab124309bb3aff0f8d49981ba71d57142bb6fa00934a963005f4fa792b4d260ff58cd4ab25592fcff764cb83cf
6
+ metadata.gz: 255e45b43495db3c4bf644a62b821bd7d8d34067f67f6be77f4bd19515d8b2813bd28e43d9612ae474bc3761f19c59286b7467f5095200e8debb7b844dcfb657
7
+ data.tar.gz: 4ad59ff0f089d070c2975a384e81a2124fbd653fb4cdb15a7388cb413fec3590f9162cf33b0ff3272f248df7d4ae11bc36e44202e794f1b59424d8180c42377a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ 0.3.5 (2014-08-24)
2
+ ------------------
3
+ * Updated project structure; new entrypoint is `code/game.rb`
4
+ * `yeah build` command through new `Web::Builder`
5
+ * `yeah new` accepts name option (thanks fixnum)
6
+ * `yeah serve` accepts port option
7
+ * `Asset`: removed `#path=`, `#to_n`
8
+ * `Image`: added `#to_n`
9
+ * `Sound`: removed `#pause`, added `#stop`
10
+ * `Web::Sound` can be played multiple times simultaneously
11
+ * Benchmarking & `Vector` benchmarks (thanks meganemura)
12
+ * `Vector` optimization (partly by meganemura)
13
+ * New project game class name is based on name option.
14
+ * Various code & documentation cleanup
15
+
1
16
  0.3.4 (2014-08-22)
2
17
  ------------------
3
18
  * Fixed `yeah version` command (thanks Chris Olszewski)
@@ -5,6 +20,7 @@
5
20
  * Flattened `Vector` math operator code
6
21
  * `Vector#magnitude` as alias for `Vector#length`
7
22
  * `Vector#unit` as alias for `Vector#normalize`
23
+ * gemspec and Gemfile minor updates
8
24
  * Updated documentation
9
25
 
10
26
  0.3.3 (2014-08-18)
data/README.md CHANGED
@@ -41,13 +41,13 @@ NOTE: This is alpha-stage software, expect changes!
41
41
 
42
42
  1. In a command line, enter `yeah new` to generate a new game project.
43
43
  2. Change into the new `game` directory, then enter `bundle install`.
44
- 3. Add game code to `code/game.rb`. No tutorials yet; please take a look at the [example code](https://github.com/yeahrb/examples) and [API reference](http://rdoc.info/github/yeahrb/yeah/9f065a6/frames).
44
+ 3. Add game code to `code/game.rb`. No tutorials yet; please take a look at the [example code](https://github.com/yeahrb/examples) and [API reference](http://rdoc.info/github/yeahrb/yeah/85e75c5/frames).
45
45
  4. Enter `yeah serve` and visit [http://localhost:1234](http://localhost:1234) to try the game.
46
46
 
47
47
 
48
48
  ## Links
49
49
 
50
- [0.3.3 API reference](http://rdoc.info/github/yeahrb/yeah/9f065a6/frames)
50
+ [0.3.4 API reference](http://rdoc.info/github/yeahrb/yeah/85e75c5/frames)
51
51
 
52
52
  [Issue & feature tracker](https://github.com/yeahrb/yeah/issues)
53
53
 
data/bin/yeah CHANGED
@@ -1,31 +1,57 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'fileutils'
3
+ command = ARGV.shift
4
4
 
5
- options = {}
5
+ case command
6
6
 
7
- options[:command] = ARGV.shift
8
-
9
- case options[:command]
10
7
  when 'new'
11
- if Dir['game'].any?
12
- puts "Error: `game` directory already exists."
8
+ require 'fileutils'
9
+
10
+ name = ARGV.shift || 'new_game'
11
+
12
+ def underscore(string)
13
+ string.split(/(?=[A-Z])/).map(&:downcase).join('_')
14
+ end
15
+
16
+ def classify(string)
17
+ string.split('_').map(&:capitalize).join
18
+ end
19
+
20
+ project_path = underscore(name)
21
+
22
+ if Dir[project_path].any?
23
+ puts "Error: `#{project_path}` directory already exists."
13
24
  else
25
+ # Use project template for new project directory.
14
26
  template_path = File.expand_path('../../lib/yeah/_template', __FILE__)
15
- FileUtils.cp_r(template_path, './game')
16
- puts "Created new game project at `game`."
27
+ FileUtils.cp_r(template_path, project_path)
28
+
29
+ # Use name for Game subclass name.
30
+ game_path = "#{project_path}/code/game.rb"
31
+ File.write(game_path, File.read(game_path) % classify(name))
32
+
33
+ puts "Created new game project at `#{project_path}`."
17
34
  end
35
+
36
+ when 'build'
37
+ require 'yeah/web/builder'
38
+ Yeah::Web::Builder.new.build
39
+
18
40
  when 'serve'
19
41
  require 'yeah/web/server'
20
- Yeah::Web::Server.new.start
42
+ port = ARGV.shift
43
+ port ? Yeah::Web::Server.new.serve(port) : Yeah::Web::Server.new.serve
44
+
21
45
  when 'version'
22
46
  require 'yeah/version'
23
47
  puts Yeah::VERSION
48
+
24
49
  else
25
50
  puts "Usage: yeah <command>"
26
51
  puts ""
27
52
  puts "Commands:"
28
- puts " new - create a new game project"
29
- puts " serve - serve a game over the Internet"
53
+ puts " new [name] - create a new game project"
54
+ puts " build - build package for a game"
55
+ puts " serve [port] - serve a game over the Internet"
30
56
  puts " version - print installed version"
31
57
  end
@@ -15,11 +15,7 @@ class Asset
15
15
  # Alias for ::new.
16
16
  end
17
17
 
18
- # @!attribute path
19
- # @param [String] path to asset relative to `assets/`
18
+ # @!attribute [r] path
20
19
  # @return [String] path to asset relative to `assets/`
21
-
22
- # @!method to_n
23
- # @return [Native] native representation of asset for platform
24
20
  end
25
21
  end
@@ -12,5 +12,8 @@ class Image < Asset
12
12
 
13
13
  # @!attribute [r] height
14
14
  # @return [Integer] height of image
15
+
16
+ # @!method to_n
17
+ # @return [Native] native reference
15
18
  end
16
19
  end
@@ -9,7 +9,7 @@ class Sound < Asset
9
9
  # @!method play
10
10
  # Play sound.
11
11
 
12
- # @!method pause
13
- # Pause sound. A following call to {#play} will resume.
12
+ # @!method stop
13
+ # Stop all playback.
14
14
  end
15
15
  end
@@ -1,4 +1,4 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'yeah', '~> 0.3.3'
3
+ gem 'yeah', '~> 0.3.5'
4
4
  gem 'opal', github: 'opal/opal', ref: '7e843b0'
@@ -1,4 +1,4 @@
1
- class NewGame < Game
1
+ class %s < Game
2
2
  def setup
3
3
  end
4
4
 
data/lib/yeah/vector.rb CHANGED
@@ -113,15 +113,17 @@ class Vector
113
113
 
114
114
  # @return [Vector] negative vector
115
115
  def -@
116
- self.class.new(*@components.map(&:-@))
116
+ self.class.new(-@components[0],
117
+ -@components[1],
118
+ -@components[2])
117
119
  end
118
120
 
119
121
  # @param [Vector] position
120
122
  # @return [Numeric] distance to a position
121
123
  def distance_to(position)
122
- Math.sqrt((x - position.x) ** 2 +
123
- (y - position.y) ** 2 +
124
- (z - position.z) ** 2)
124
+ Math.sqrt((@components[0] - position.x) ** 2 +
125
+ (@components[1] - position.y) ** 2 +
126
+ (@components[2] - position.z) ** 2)
125
127
  end
126
128
 
127
129
  # @param [Vector] position
@@ -135,15 +137,16 @@ class Vector
135
137
  # @param [Numeric] distance to move
136
138
  # @return [Vector] position moved along an angle for a distance in 2D
137
139
  def along(angle, distance)
138
- self.class.new(x + Math.cos(angle) * distance,
139
- y + Math.sin(angle) * distance)
140
+ self.class.new(@components[0] + Math.cos(angle) * distance,
141
+ @components[1] + Math.sin(angle) * distance)
140
142
  end
141
143
 
142
144
  # @param (see #along)
143
145
  # @return [Vector] self after moving along an angle for a distance in 2D
144
146
  def along!(angle, distance)
145
- self.x += Math.cos(angle) * distance
146
- self.y += Math.sin(angle) * distance
147
+ @components[0] += Math.cos(angle) * distance
148
+ @components[1] += Math.sin(angle) * distance
149
+
147
150
  self
148
151
  end
149
152
 
data/lib/yeah/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yeah
2
- VERSION = '0.3.4'
2
+ VERSION = '0.3.5'
3
3
  end
@@ -0,0 +1,93 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'erb'
4
+ require 'opal'
5
+
6
+ module Yeah
7
+ module Web
8
+
9
+ # `Web::Builder` builds a game into a standalone package that is playable
10
+ # through a web browser. To build a game, enter `yeah build` in a command-line
11
+ # within a game project.
12
+ # @todo DRY internals with `Web::Server`.
13
+ class Builder
14
+ # @return [nil]
15
+ # Build game in working directory.
16
+ def build
17
+ make_build_dirs
18
+ setup_compiler
19
+ compile
20
+
21
+ puts "Built game package to `build/web/`."
22
+ end
23
+
24
+ private
25
+
26
+ def make_build_dirs
27
+ # Make build directories.
28
+ FileUtils.mkpath 'build/web/assets/yeah/web'
29
+ end
30
+
31
+ def setup_compiler
32
+ @compiler = Opal::Environment.new
33
+
34
+ # Append standard library code paths.
35
+ $LOAD_PATH.each { |p| @compiler.append_path(p) }
36
+
37
+ # Append gem code paths.
38
+ @compiler.append_path gem_path.join('lib')
39
+ @compiler.append_path gem_path.join('opal')
40
+
41
+ # Append game code and asset paths.
42
+ @compiler.append_path 'assets'
43
+ @compiler.append_path 'code'
44
+ end
45
+
46
+ def compile
47
+ runner_path = Pathname.new(__FILE__).join('..', 'runner.html.erb')
48
+ html = ERB.new(File.read(runner_path)).result(binding)
49
+ File.write('build/web/runner.html', html)
50
+ end
51
+
52
+ def asset_include_tags
53
+ paths = Dir['assets/**/*'].select { |p| File.file? p }
54
+
55
+ paths.map do |path|
56
+ copy_asset(path)
57
+
58
+ case path
59
+ when /\.(ogg|wav|mp3)$/
60
+ "<audio src=\"./#{path}\"></audio>"
61
+ else
62
+ "<img src=\"./#{path}\" />"
63
+ end
64
+ end.join("\n")
65
+ end
66
+
67
+ def script_include_tag(path)
68
+ build_script(path)
69
+
70
+ "<script src=\"./assets/#{path}.js\"></script>"
71
+ end
72
+
73
+ def copy_asset(path)
74
+ destination_path = build_path.join(path)
75
+ FileUtils.mkpath(destination_path.join('..'))
76
+ FileUtils.cp(path, destination_path)
77
+ end
78
+
79
+ def build_script(path)
80
+ File.write(build_path.join("assets/#{path}.js"), @compiler[path].to_s)
81
+ end
82
+
83
+ def build_path
84
+ @build_path ||= Pathname.new("build/web")
85
+ end
86
+
87
+ def gem_path
88
+ @gem_path ||= Pathname.new(__FILE__).join('..', '..', '..', '..')
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -47,15 +47,15 @@
47
47
  <canvas></canvas>
48
48
 
49
49
  <div class="hidden">
50
- <%= @server.asset_include_tags %>
50
+ <%= asset_include_tags %>
51
51
  </div>
52
52
 
53
- <%= javascript_include_tag 'yeah/web/dependencies' %>
54
- <%= javascript_include_tag 'yeah/web' %>
55
- <%= javascript_include_tag 'yeah/web/setup' %>
53
+ <%= script_include_tag 'yeah/web/dependencies' %>
54
+ <%= script_include_tag 'yeah/web' %>
55
+ <%= script_include_tag 'yeah/web/setup' %>
56
56
 
57
- <%= javascript_include_tag 'code' %>
57
+ <%= script_include_tag 'game' %>
58
58
 
59
- <%= javascript_include_tag 'yeah/web/start' %>
59
+ <%= script_include_tag 'yeah/web/start' %>
60
60
  </body>
61
61
  </html>
@@ -1,60 +1,85 @@
1
1
  require 'pathname'
2
+ require 'erb'
2
3
  require 'rack'
3
4
  require 'opal'
4
5
 
5
6
  module Yeah
6
7
  module Web
7
8
 
8
- # The `Web::Server` serves a game over the Internet. It can be started easily
9
- # by entering `yeah serve` in a command-line within a game project.
9
+ # The `Web::Server` serves a game over the web. To serve a game, enter
10
+ # `yeah serve` in a command-line within a game project.
10
11
  class Server
11
12
  # @param [Integer] port to serve game over
12
- # Start serving the game.
13
- def start(port = 1234)
14
- Rack::Server.start(app: Application.new, Port: port)
15
- end
13
+ # @return [nil]
14
+ # Serve game in working directory.
15
+ def serve(port = 1234)
16
+ runner = Runner.new
16
17
 
17
- private
18
+ assets = Opal::Environment.new
18
19
 
19
- # For internal usage.
20
- # @see Yeah::Web::Server
21
- class Application < Opal::Server
22
- def initialize
23
- @index_path = gem_path.join('lib', 'yeah', 'web', 'runner.html.erb').to_s
20
+ # Append standard library code paths.
21
+ $LOAD_PATH.each { |p| assets.append_path(p) }
24
22
 
25
- super
23
+ # Append gem code paths.
24
+ assets.append_path gem_path.join('lib')
25
+ assets.append_path gem_path.join('opal')
26
26
 
27
- # Append stdlib paths
28
- $LOAD_PATH.each { |p| append_path(p) }
27
+ # Append game code and asset paths.
28
+ assets.append_path 'assets'
29
+ assets.append_path 'code'
29
30
 
30
- # Append Yeah paths
31
- append_path gem_path.join('lib')
32
- append_path gem_path.join('opal')
31
+ application = Rack::Builder.new do
32
+ use Rack::Deflater
33
33
 
34
- # Append game (working directory) paths
35
- append_path 'assets'
36
- append_path 'code'
34
+ map '/' do
35
+ run runner
36
+ end
37
+
38
+ map '/assets' do
39
+ run assets
40
+ end
37
41
  end
38
42
 
43
+ Rack::Server.start(app: application, Port: port)
44
+ end
45
+
46
+ private
47
+
48
+ def gem_path
49
+ @gem_path ||= Pathname.new(__FILE__).join('..', '..', '..', '..')
50
+ end
51
+
52
+ # `Web::Runner` is a Rack app that provides the runner webpage for
53
+ # `Web::Server`.
54
+ # @see Yeah::Web::Server
55
+ class Runner
56
+ def call(environment)
57
+ runner_path = Pathname.new(__FILE__).join('..', 'runner.html.erb')
58
+ html = ERB.new(File.read(runner_path)).result(binding)
59
+
60
+ [200, {'Content-Type' => 'text/html'}, [html]]
61
+ end
62
+
63
+ private
64
+
39
65
  def asset_include_tags
40
66
  paths = Dir['assets/**/*'].select { |p| File.file? p }
41
67
 
42
68
  paths.map do |path|
43
69
  case path
44
70
  when /\.(ogg|wav|mp3)$/
45
- "<audio src=\"#{path}\"></audio>"
71
+ "<audio src=\"/#{path}\"></audio>"
46
72
  else
47
- "<img src=\"#{path}\" />"
73
+ "<img src=\"/#{path}\" />"
48
74
  end
49
75
  end.join("\n")
50
76
  end
51
77
 
52
- private
53
-
54
- def gem_path
55
- @gem_path ||= Pathname.new(__FILE__).join('..', '..', '..', '..')
78
+ def script_include_tag(path)
79
+ "<script src=\"/assets/#{path}.js\"></script>"
56
80
  end
57
81
  end
58
82
  end
83
+
59
84
  end
60
85
  end
@@ -3,6 +3,8 @@ module Web
3
3
  class Asset
4
4
  ASSETS_PATH = "./assets"
5
5
 
6
+ attr_reader :path
7
+
6
8
  class << self
7
9
  def [](*args)
8
10
  new(*args)
@@ -10,28 +12,13 @@ class Asset
10
12
  end
11
13
 
12
14
  def initialize(path)
13
- setup_native
14
-
15
- self.path = path
16
- end
17
-
18
- def path
19
- `#@native.src`.sub(/.*:\/\/.*#{ASSETS_PATH}\//i, '')
20
- end
21
- def path=(val)
22
- # TODO: use Pathname#join if it is implemented in Opal
23
- full_path = "#{ASSETS_PATH}/#{val}"
24
- `#@native.src = #{full_path};`
25
- end
26
-
27
- def to_n
28
- @native
15
+ @path = path
29
16
  end
30
17
 
31
18
  private
32
19
 
33
- def setup_native
34
- raise NotImplementedError
20
+ def full_path
21
+ "#{ASSETS_PATH}/#{@path}"
35
22
  end
36
23
  end
37
24
  end
@@ -1,6 +1,15 @@
1
1
  module Yeah
2
2
  module Web
3
3
  class Image < Asset
4
+ def initialize(path)
5
+ super
6
+
7
+ %x{
8
+ #@native = new Image();
9
+ #@native.src = #{full_path};
10
+ }
11
+ end
12
+
4
13
  def size
5
14
  V[`#@native.width`, `#@native.height`]
6
15
  end
@@ -13,10 +22,8 @@ class Image < Asset
13
22
  `#@native.height`
14
23
  end
15
24
 
16
- private
17
-
18
- def setup_native
19
- `#@native = new Image();`
25
+ def to_n
26
+ @native
20
27
  end
21
28
  end
22
29
  end
@@ -1,18 +1,49 @@
1
1
  module Yeah
2
2
  module Web
3
3
  class Sound < Asset
4
- def play
5
- `#@native.play()`
6
- end
4
+ `window.AudioContext = window.AudioContext || window.webkitAudioContext`
5
+ CONTEXT = `new AudioContext()`
6
+
7
+ def initialize(path)
8
+ super
9
+
10
+ @sources = []
11
+
12
+ %x{
13
+ var request = new XMLHttpRequest();
14
+ request.open('GET', #{full_path}, true);
15
+ request.responseType = 'arraybuffer';
16
+
17
+ request.onload = function() {
18
+ #{CONTEXT}.decodeAudioData(request.response, function(buffer) {
19
+ #@buffer = buffer;
20
+ });
21
+ }
7
22
 
8
- def pause
9
- `#@native.pause()`
23
+ request.send();
24
+ }
10
25
  end
11
26
 
12
- private
27
+ def play
28
+ return unless @buffer
29
+
30
+ %x{
31
+ var source = #{CONTEXT}.createBufferSource();
32
+ source.buffer = #@buffer;
33
+ source.connect(#{CONTEXT}.destination);
34
+
35
+ #{@sources << `source`}
36
+
37
+ source.onended = function() {
38
+ #{@sources.shift}
39
+ }
40
+
41
+ source.start(0);
42
+ }
43
+ end
13
44
 
14
- def setup_native
15
- ` #@native = new Audio()`
45
+ def stop
46
+ @sources.each { |s| `try { #{s}.stop(0) } catch(e) {}`; nil }
16
47
  end
17
48
  end
18
49
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yeah
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artur Ostrega
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-22 00:00:00.000000000 Z
11
+ date: 2014-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -101,7 +101,6 @@ files:
101
101
  - lib/yeah/_platform/sound.rb
102
102
  - lib/yeah/_platform/ticker.rb
103
103
  - lib/yeah/_template/Gemfile
104
- - lib/yeah/_template/code/code.rb
105
104
  - lib/yeah/_template/code/game.rb
106
105
  - lib/yeah/_web.rb
107
106
  - lib/yeah/color.rb
@@ -109,6 +108,7 @@ files:
109
108
  - lib/yeah/game.rb
110
109
  - lib/yeah/vector.rb
111
110
  - lib/yeah/version.rb
111
+ - lib/yeah/web/builder.rb
112
112
  - lib/yeah/web/dependencies.rb
113
113
  - lib/yeah/web/runner.html.erb
114
114
  - lib/yeah/web/server.rb
@@ -1,4 +0,0 @@
1
- # Entry point
2
- # Specify dependencies and game code require order here.
3
-
4
- require 'game'