yeah 0.2.0 → 0.2.2

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: d01dc8962df50d909356224581bb6c5e566991f5
4
- data.tar.gz: 789fa6d989ad7422f05e1b13fd1c2bea2718c128
3
+ metadata.gz: 3ca889c593c853c056b2945402f87240a708abc3
4
+ data.tar.gz: 1a215b41c68cf68ff4ead5d5a77589dcfc2f92c4
5
5
  SHA512:
6
- metadata.gz: a0ae07e88b7f9334db886be3caf5497d95528bdeaa69eb82ed24a56885f04426088e1878758732afd0ca33d4d327a640fe30fa38ed156f7ff425591717600ef9
7
- data.tar.gz: 82e2bdb785e40f172378eeafc06e6c091ec0769fd06e7e8cd64a1806270526e3d18f811e50720efadd816617f73875d6d9f8d62f1702ceea84c4131dd626959b
6
+ metadata.gz: c4d99208cb6cbd3f8e86b37f4dcb0b7492233d4a3879cf1cd00fca8662306bcf5c4302c8a9c877c56cf7b81dd89b300f59b57343fb50f1d9fa8c2f9442c7ee83
7
+ data.tar.gz: 172905029424fa4dbad2bd7b9db2b892a4f963a14c9d72ddc4645506124996ee46c4ce96d84bb7ec1fe4b38a7674bfddfcf77e7bbf4d0864d60f3eb943979c2e
data/CHANGELOG.md CHANGED
@@ -1,7 +1,28 @@
1
- ## 0.1.0 [2013-09-05]
2
- * Added basic Vector, Entity and Game classes.
1
+ ## 0.2.3 [pend]
2
+ * Yemo demo
3
+
4
+ ## 0.2.2 [2013-11-12]
5
+ * Shootguy -> Vyzer
6
+ * Expanded and revised Vyzer demo
7
+ * Optimized drawing
8
+ * Input interface
9
+ * Entity-Game relationship
10
+ * Entity subpositions and basic collision detection
11
+ * 16:9 default resolution
12
+ * Basic Map API
13
+ * Vector V shorthand
14
+ * Misc.
15
+
16
+ ## 0.2.1 [2013-10-18]
17
+ * Shootguy demo/API model
18
+ * Cleanup
19
+ * Documentation
20
+ * Misc.
3
21
 
4
22
  ## 0.2.0 [2013-09-21]
5
23
  * Added Color, Surface, Rectangle, Map and Desktop classes.
6
24
  * Extended Vector, Entity and Game classes.
7
25
  * Added Happy Rectangle demo.
26
+
27
+ ## 0.1.0 [2013-09-05]
28
+ * Added basic Vector, Entity and Game classes.
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  Yeah
2
2
  ====
3
- A Ruby video game framework that prioritizes happiness and agility over raw performance.
3
+ An early-stage Ruby video game framework that optimizes for development efficiency.
4
4
 
5
- > Premature optimization is the root of all evil. - Donald Knuth
5
+ It is in very early stages, but at version 0.3.0 the Vyzer demo should be functional. Any version below 1.0.0 is unstable and lacks backward compatibility.
6
6
 
7
7
  Planned features
8
8
  ----------------
@@ -10,3 +10,11 @@ Planned features
10
10
  * Command line initialization script to help one hit the ground running.
11
11
  * Graphical tools for creating video game resources like sprites and maps.
12
12
  * Multiple target platforms, starting with desktop and web.
13
+
14
+ Installation
15
+ ------------
16
+ Install with `gem install yeah`. Yeah depends on Rubygame, which depends on SDL; see [these guides](https://github.com/rubygame/rubygame/wiki/Install).
17
+
18
+ Blog
19
+ ----
20
+ [Why am I making Yeah?](http://skofo.github.io/blog/why-am-i-making-yeah)
@@ -0,0 +1,6 @@
1
+ class Numeric
2
+ def limit(value)
3
+ sign_mult = self <=> 0
4
+ self.abs > value.abs ? value * sign_mult : self
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module Yeah::BasicPhysics
2
+ attr_writer :velocity
3
+
4
+ def velocity
5
+ @velocity ||= V[0, 0, 0]
6
+ end
7
+
8
+ def move
9
+ self.position += @velocity
10
+ end
11
+ end
data/lib/yeah/color.rb CHANGED
@@ -1,22 +1,25 @@
1
+ # Color.
1
2
  class Yeah::Color
3
+ # @!attribute rgba_bytes
4
+ # @return [Array<(Integer, Integer, Integer, Integer)>] red, green, blue,
5
+ # alpha bytes
2
6
  attr_accessor :rgba_bytes
3
7
 
4
8
  class << self
5
9
  alias_method :[], :new
6
10
  end
7
11
 
8
- def initialize(*arguments)
9
- arguments = [0, 0, 0, 255] if arguments.empty?
12
+ def initialize(*values)
13
+ default_values = [0, 0, 0, 255]
14
+ values += default_values[values.size..-1]
15
+ @rgba_bytes = values
16
+ end
10
17
 
11
- case arguments[0]
12
- when Numeric
13
- @rgba_bytes = [*arguments]
14
- when Array
15
- @rgba_bytes = arguments[0]
16
- end
18
+ def inspect
19
+ "#{self.class.name}[#{rgba_bytes.join(', ')}]"
17
20
  end
18
21
 
19
22
  def ==(other)
20
- self.class == other.class && @rgba_bytes == other.rgba_bytes ? true : false
23
+ self.class == other.class && @rgba_bytes == other.rgba_bytes
21
24
  end
22
25
  end
data/lib/yeah/desktop.rb CHANGED
@@ -1,12 +1,25 @@
1
1
  require 'rubygame'
2
2
 
3
+ # Bindings to the native desktop powered by Rubygame.
3
4
  class Yeah::Desktop
5
+ # @!attribute [r] screen
6
+ # @return [Rubygame::Screen]
7
+ # @!attribute resolution
8
+ # @return [Vector] size of game window
9
+ # @!attribute tickrate
10
+ # @return [Integer] target ticks per second
4
11
  attr_reader :screen, :resolution, :tickrate
5
12
 
6
- def initialize(resolution=Vector[320, 240])
13
+ def initialize(resolution=V[320, 180])
7
14
  self.resolution = resolution
15
+
8
16
  @clock = Rubygame::Clock.new
9
17
  self.tickrate = 30
18
+
19
+ @pressables = {}
20
+ pressables_keys = [(:a..:z).to_a, (:A..:Z).to_a, (0..9).to_a,
21
+ :up, :down, :left, :right].flatten
22
+ pressables_keys.each { |pk| @pressables[pk] = false }
10
23
  end
11
24
 
12
25
  def resolution=(value)
@@ -14,21 +27,46 @@ class Yeah::Desktop
14
27
  @resolution = value
15
28
  end
16
29
 
17
- def render(surface)
18
- struct = screen.send(:struct)
19
- struct.pixels.write_string(surface.data(:bgra), surface.data.length)
20
- screen.update
21
- end
22
-
23
30
  def tickrate=(value)
24
31
  @clock.target_framerate = value
25
32
  @tickrate = value
26
33
  end
27
34
 
35
+ # Project a surface onto screen.
36
+ # @param [Surface]
37
+ def render(surface)
38
+ masks = [0x0000ff, 0x00ff00, 0xff0000, 0]
39
+ rg_surface = Rubygame::Surface.new(surface.size.to_a[0..1], masks: masks)
40
+ rg_surface.pixels = surface.data
41
+ rg_surface.blit(screen, [0, 0])
42
+ screen.update
43
+ end
44
+
45
+ # Execute passed block on each tick.
46
+ # @yield
28
47
  def each_tick
29
48
  loop do
30
49
  yield
31
50
  @clock.tick
32
51
  end
33
52
  end
53
+
54
+ # Press a key or button.
55
+ # @param [Symbol|Integer] key or button
56
+ def press(pressable)
57
+ @pressables[pressable] = true
58
+ end
59
+
60
+ # Release a key or button.
61
+ # @param [Symbol|Integer] key or button
62
+ def release(pressable)
63
+ @pressables[pressable] = false
64
+ end
65
+
66
+ # Is a key or button being pressed?
67
+ # @param [Symbol|Integer] key or button
68
+ def pressing?(*pressables)
69
+ raise ArgumentError if pressables.empty?
70
+ pressables.any? { |p| @pressables[p] }
71
+ end
34
72
  end
data/lib/yeah/entity.rb CHANGED
@@ -1,35 +1,137 @@
1
+ # Game object.
1
2
  class Yeah::Entity
2
- attr_accessor :position, :visual
3
+ # @!attribute position
4
+ # @return [Vector] position within a game
5
+ # @!attribute size
6
+ # @return [NilClass|Vector] visual size
7
+ # @!attribute state
8
+ # @return [Symbol] state in game
9
+ # @!attribute visual
10
+ # @return [Visual] visual representation within a game
11
+ # @!attribute game
12
+ # @return [Game] game to which this belongs to
13
+ attr_accessor :position, :state, :visual
14
+ attr_reader :game
15
+ attr_writer :size
3
16
 
4
- def initialize(position=Vector[])
17
+ def initialize(position=V[])
5
18
  @position = position
6
19
  end
7
20
 
8
- def x
9
- @position.x
21
+ class << self
22
+ def define_position_helpers
23
+ %w(x y z).each_with_index do |coord, i|
24
+ define_method(coord) { @position[i] }
25
+ define_method("#{coord}=") { |val| @position[i] = val }
26
+ end
27
+ end
10
28
  end
11
29
 
12
- def x=(value)
13
- @position.x = value
30
+ def size
31
+ @size || visual && visual.size || V[]
14
32
  end
15
33
 
16
- def y
17
- @position.y
34
+ def game=(value)
35
+ @game = value
36
+ @game.entities << self unless @game.entities.include? self
18
37
  end
19
38
 
20
- def y=(value)
21
- @position.y = value
39
+ # @!attribute x
40
+ # @return [Vector] position.x
41
+ # @!attribute y
42
+ # @return [Vector] position.y
43
+ # @!attribute z
44
+ # @return [Vector] position.z
45
+ define_position_helpers
46
+
47
+ # Update entity.
48
+ def update
22
49
  end
23
50
 
24
- def z
25
- @position.z
51
+ # Get visual representation from visual.
52
+ # @return [Surface] visual representation
53
+ def draw
54
+ visual.draw if visual
26
55
  end
27
56
 
28
- def z=(value)
29
- @position.z = value
57
+ def pressing?(pressable)
58
+ game.pressing? pressable
30
59
  end
31
60
 
32
- def draw
33
- visual.draw if visual
61
+ def control(attrName, input, value)
62
+ if input.class == Array
63
+ polarity = 0
64
+ polarity += 1 if game.platform.pressing?(input.first)
65
+ polarity -= 1 if game.platform.pressing?(input.last)
66
+ else
67
+ polarity = game.platform.pressing?(input) ? 1 : -1
68
+ end
69
+
70
+ self.instance_eval("#{attrName} += #{value} * #{polarity}")
71
+ end
72
+
73
+ # X of right edge.
74
+ # @return [Integer]
75
+ def right
76
+ position.x + size.x
77
+ end
78
+
79
+ # X of left edge.
80
+ # @return [Integer]
81
+ def left
82
+ position.x
83
+ end
84
+
85
+ # Y of top edge.
86
+ # @return [Integer]
87
+ def top
88
+ position.y + size.y
89
+ end
90
+
91
+ # Y of bottom edge.
92
+ # @return [Integer]
93
+ def bottom
94
+ position.y
95
+ end
96
+
97
+ # Z of front edge.
98
+ # @return [Integer]
99
+ def front
100
+ position.z + size.z
101
+ end
102
+
103
+ # Z of back edge.
104
+ # @return [Integer]
105
+ def back
106
+ position.z
107
+ end
108
+
109
+ # Coordinate of center.
110
+ # @return [Vector]
111
+ def center
112
+ position + size / 2
113
+ end
114
+
115
+ # Is intersected with other entity or entity of subclass?
116
+ # @return [Boolean]
117
+ def touching?(other)
118
+ return false if other == self
119
+
120
+ if other.is_a?(Class)
121
+ if game
122
+ return game.entities.select { |e| e.is_a? other }
123
+ .any? { |e| touching? e }
124
+ else
125
+ return false
126
+ end
127
+ end
128
+
129
+ return false if size == V[] || other.size == V[]
130
+
131
+ not_touching_x = left > other.right || right < other.left
132
+ not_touching_y = bottom > other.top || top < other.bottom
133
+ not_touching_z = back > other.front || front < other.back
134
+
135
+ !(not_touching_x && not_touching_y && not_touching_z)
34
136
  end
35
137
  end
data/lib/yeah/game.rb CHANGED
@@ -1,13 +1,44 @@
1
+ # Manages entities.
1
2
  class Yeah::Game
2
- attr_accessor :entities, :screen, :platform, :resolution
3
+ # @!attribute resolution
4
+ # @return [Vector] size of screen
5
+ # @!attribute screen
6
+ # @return [Surface] visual render
7
+ # @!attribute [r] platform
8
+ # @return [Platform] underlying platform bindings
9
+ # @!attribute entities
10
+ # @return [Array] active entities
11
+ attr_accessor :resolution, :screen
12
+ attr_reader :entities, :platform
3
13
 
4
14
  def initialize
5
- @resolution = Vector[320, 240]
15
+ @resolution = V[320, 180]
6
16
  @screen = Surface.new(@resolution)
7
17
  @platform = Desktop.new
8
18
  @entities = []
9
19
  end
10
20
 
21
+ # Start the game loop.
22
+ def start
23
+ platform.each_tick do
24
+ update
25
+ draw
26
+ break if @stopped
27
+ end
28
+ end
29
+
30
+ # Stop the game loop.
31
+ def stop
32
+ @stopped = true
33
+ end
34
+
35
+ def entities=(value)
36
+ @entities = value
37
+ @entities.each { |e| e.game = self }
38
+ end
39
+
40
+ protected
41
+
11
42
  def update
12
43
  @entities.each { |e| e.update }
13
44
  end
@@ -20,11 +51,4 @@ class Yeah::Game
20
51
  end
21
52
  platform.render(screen)
22
53
  end
23
-
24
- def start
25
- platform.each_tick do
26
- update
27
- draw
28
- end
29
- end
30
54
  end
data/lib/yeah/map.rb CHANGED
@@ -1,7 +1,40 @@
1
+ # A map of entities for a Game.
1
2
  class Yeah::Map
2
- attr_accessor :background
3
+ # @!attribute background
4
+ # @return [Color] background color
5
+ # @!attribute key
6
+ # @return [Hash] tile key
7
+ # @!attribute tile_size
8
+ # @return [Vector] size of each character in #tiles
9
+ # @!attribute tiles
10
+ # @return [Array<String>] entities at relative positions
11
+ attr_accessor :background, :key, :tile_size, :tiles
12
+
13
+ def self.background(background)
14
+ @@background = background
15
+ end
16
+
17
+ def self.key(key)
18
+ @@key = key
19
+ end
20
+
21
+ def self.tile_size(tile_size)
22
+ @@tile_size = tile_size
23
+ end
24
+
25
+ def self.tiles(tiles)
26
+ @@tiles = tiles
27
+ end
3
28
 
4
29
  def initialize
5
- @background = Color[]
30
+ @background = @@background || Color[]
31
+ @key = @@key ||= {}
32
+ @tile_size = @@tile_size ||= nil
33
+ @tiles = @@tiles ||= []
34
+ end
35
+
36
+ def key=(key)
37
+ @key = key
38
+ self.tile_size = @key.first.last.new.size if @key.first && tile_size.nil?
6
39
  end
7
40
  end
@@ -1,11 +1,18 @@
1
+ # Colored rectangle Visual.
1
2
  class Yeah::Rectangle
3
+ # @!attribute size
4
+ # @return [Vector]
5
+ # @!attribute color
6
+ # @return [Color]
2
7
  attr_accessor :size, :color
3
8
 
4
- def initialize(size=Vector[], color=Color[*[255]*4])
9
+ def initialize(size=V[], color=Color[*[255]*4])
5
10
  @size = size
6
11
  @color = color
7
12
  end
8
13
 
14
+ # Surface representation.
15
+ # @return [Surface]
9
16
  def draw
10
17
  surface = Surface.new(size)
11
18
  surface.fill(color)
data/lib/yeah/surface.rb CHANGED
@@ -1,8 +1,14 @@
1
+ # Rectangular pixel data.
1
2
  class Yeah::Surface
3
+ # @!attribute size
4
+ # @return [Vector]
5
+ # @!attribute data
6
+ # @param [Symbol] color byte order (:rgba or :bgra)
7
+ # @return [String] pixel data as string of bytes
2
8
  attr_reader :size
3
- attr_writer :data
9
+ attr_accessor :data
4
10
 
5
- def initialize(size=Vector[])
11
+ def initialize(size=V[])
6
12
  self.size = size
7
13
  end
8
14
 
@@ -11,15 +17,9 @@ class Yeah::Surface
11
17
  @data = "\x00" * 4 * size.x * size.y
12
18
  end
13
19
 
14
- def data(format=:rgba)
15
- case format
16
- when :rgba
17
- @data
18
- when :bgra
19
- @data.scan(/.{4}/).map { |p| p[2] + p[1] + p[0] + p[3] }.join
20
- end
21
- end
22
-
20
+ # Color of pixel at a position.
21
+ # @param [Vector] position of pixel
22
+ # @return [Color]
23
23
  def color_at(position)
24
24
  data_lines = data.scan(/.{#{size.x*4}}/)
25
25
  line = data_lines[position.y]
@@ -29,7 +29,11 @@ class Yeah::Surface
29
29
  Color[*color_bytes]
30
30
  end
31
31
 
32
- def fill(color, position1=Vector[0, 0], position2=size-1)
32
+ # Fill a rectangular area with a color.
33
+ # @param [Color] fill color
34
+ # @param [Vector] position of first corner
35
+ # @param [Vector] position of other corner
36
+ def fill(color, position1=V[0, 0], position2=size-1)
33
37
  color_byte_string = color.rgba_bytes.pack('C*')
34
38
  data_lines = data.scan(/.{#{size.x*4}}/)
35
39
 
@@ -43,7 +47,10 @@ class Yeah::Surface
43
47
  @data = data_lines.join
44
48
  end
45
49
 
46
- def draw(surface, position=Vector[0, 0])
50
+ # Draw onto other surface.
51
+ # @param [Surface] surface to draw on
52
+ # @param [Vector] position to draw on other surface
53
+ def draw(surface, position=V[0, 0])
47
54
  data_lines = data.scan(/.{#{size.x*4}}/)
48
55
  surface_data_lines = surface.data.scan(/.{#{surface.size.x*4}}/)
49
56
 
data/lib/yeah/vector.rb CHANGED
@@ -1,6 +1,18 @@
1
+ # Three-dimensional geometric vector. Used as position or size.
1
2
  class Yeah::Vector
2
- class << self
3
- alias_method :[], :new
3
+ # @!attribute components
4
+ # @return [Array<(Numeric, Numeric, Numeric)>]
5
+ # @!attribute [r] to_a
6
+ # @see components
7
+ # @!attribute []
8
+ # @param [Integer] *n* of component
9
+ # @return [Numeric] *n*th component
10
+ attr_reader :components
11
+ alias_method :to_a, :components
12
+
13
+ def self.random(*component_maxes)
14
+ components = component_maxes.map { |cm| Random.rand(cm) }
15
+ self.new(*components)
4
16
  end
5
17
 
6
18
  def initialize(*components)
@@ -12,8 +24,8 @@ class Yeah::Vector
12
24
  self.components = components
13
25
  end
14
26
 
15
- def components
16
- @components
27
+ def inspect
28
+ "#{self.class.name}[#{components.join(', ')}]"
17
29
  end
18
30
 
19
31
  def components=(values)
@@ -25,6 +37,22 @@ class Yeah::Vector
25
37
  @components = values + [0] * (3 - values.size)
26
38
  end
27
39
 
40
+ class << self
41
+ alias_method :[], :new
42
+
43
+ def define_component_helpers
44
+ component_name_sets = [[:x, :width], [:y, :height], [:z, :depth]]
45
+ component_name_sets.each_with_index do |set, ci|
46
+ set.each do |name|
47
+ define_method(name) { @components[ci] }
48
+ define_method("#{name}=") { |val| @components[ci] = val }
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ define_component_helpers
55
+
28
56
  def ==(other)
29
57
  other.class == self.class && @components == other.components ? true : false
30
58
  end
@@ -85,46 +113,25 @@ class Yeah::Vector
85
113
  self.class[*components]
86
114
  end
87
115
 
88
- def x
89
- @components[0]
90
- end
91
- alias_method :width, :x
92
-
93
- def y
94
- @components[1]
95
- end
96
- alias_method :height, :y
97
-
98
- def z
99
- @components[2]
100
- end
101
- alias_method :depth, :z
102
-
103
- def x=(value)
104
- @components[0] = value
105
- end
106
- alias_method :width=, :x=
107
-
108
- def y=(value)
109
- @components[1] = value
110
- end
111
- alias_method :height=, :y=
112
-
113
- def z=(value)
114
- @components[2] = value
115
- end
116
- alias_method :depth=, :z=
117
-
118
- def norm
116
+ # @return [Numeric]
117
+ def magnitude
119
118
  Math.sqrt(@components.reduce(0) { |m, c| m + c*c })
120
119
  end
121
- alias_method :magnitude, :norm
122
- alias_method :length, :norm
123
- alias_method :distance, :norm
124
- alias_method :speed, :norm
125
-
120
+ # @!attribute length
121
+ # @see magnitude
122
+ # @!attribute distance
123
+ # @see magnitude
124
+ # @!attribute speed
125
+ # @see magnitude
126
+ alias_method :length, :magnitude
127
+ alias_method :distance, :magnitude
128
+ alias_method :speed, :magnitude
129
+
130
+ # Reset every component to 0.
126
131
  def reset
127
132
  @components = [0, 0, 0]
128
- self
129
133
  end
130
134
  end
135
+
136
+ # Shorthand for Vector.
137
+ Yeah::V = Yeah::Vector
data/lib/yeah.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  module Yeah
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.2'
3
3
  end
4
4
 
5
- requires = %i(vector color surface rectangle entity map desktop game)
6
- requires.each do |req|
5
+ require 'monkey/numeric'
6
+
7
+ yeah_requires = %i(vector color surface rectangle entity map desktop game
8
+ basic_physics)
9
+ yeah_requires.each do |req|
7
10
  require "yeah/#{req}"
8
11
  end