yeah 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
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'