yeah 0.2.0 → 0.2.2

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: 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