chingu 0.5.8.2 → 0.5.9

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.
data.tar.gz.sig CHANGED
Binary file
data/README.rdoc CHANGED
@@ -71,15 +71,18 @@ It currently has to be namespaced to Chingu::Traits for "has_trait" to work insi
71
71
  == OTHER CLASSES / HELPERS
72
72
 
73
73
  === Chingu::Text
74
- Makes use of Gosu::Font more rubyish and powerful.
75
- In it's core, another Chingu::GameObject + Gosu::Font.
74
+ Makes use of Image#from_text more rubyish and powerful.
75
+ In it's core, another Chingu::GameObject + image genning with Image#from_text.
76
76
 
77
77
  === Chingu::Animation
78
78
  Load and interact with tile-based animations. loop, bounce and access invidual frame(s) easily.
79
- An "@image = @animation.next!" in your Player#update is usually enough to get you started!
79
+ An "@image = @animation.next" in your Player#update is usually enough to get you started!
80
80
 
81
81
  === Chingu::Parallax
82
- A class for easy paralaxxscrolling. See example3.rb for more.
82
+ A class for easy parallaxscrolling. Add layers with different damping, move the camera to generate a new snapshot. See example3.rb for more.
83
+
84
+ === Chingu::HighScoreList
85
+ A class to keep track of high scores, limit the list, automatic sorting on score, save/load to disc. See example13.rb for more.
83
86
 
84
87
  === Various Helpers
85
88
  Both $window and game states gets some new graphical helpers, currently only 3, but quite useful:
@@ -147,7 +150,7 @@ You're probably familiar with this very common Gosu pattern:
147
150
  Game.new.show # Start the Game update/draw loop!
148
151
 
149
152
 
150
- Chingu doesn't change any fundamental concept of Gosu, but it will make the above code cleaner:
153
+ Chingu doesn't change the fundamental concept/flow of Gosu, but it will make the above code cleaner:
151
154
 
152
155
  #
153
156
  # We use Chingu::Window instead of Gosu::Window
@@ -157,7 +160,7 @@ Chingu doesn't change any fundamental concept of Gosu, but it will make the abov
157
160
  super # This is always needed if you want to take advantage of what chingu offers
158
161
  #
159
162
  # Player will automaticly be updated and drawn since it's a Chingu::GameObject
160
- # You'll need your own Game#update/#draw after a while, but just put #super there and Chingu can do its thing.
163
+ # You'll need your own Chingu::Window#update and Chingu::Window#draw after a while, but just put #super there and Chingu can do its thing.
161
164
  #
162
165
  @player = Player.create
163
166
  @player.input = {:left => :move_left, :right => :move_right}
@@ -166,7 +169,8 @@ Chingu doesn't change any fundamental concept of Gosu, but it will make the abov
166
169
 
167
170
  #
168
171
  # If we create classes from Chingu::GameObject we get stuff for free.
169
- # The accessors: image,x,y,zorder,angle,factor_x,factor_y,center_x,center_y,mode,update,draw
172
+ # The accessors image,x,y,zorder,angle,factor_x,factor_y,center_x,center_y,mode,alpha.
173
+ # We also get a default #draw which draws the image to screen with the parameters listed above.
170
174
  # You might recognize those from #draw_rot - http://www.libgosu.org/rdoc/classes/Gosu/Image.html#M000023
171
175
  # And in it's core, that's what Chingu::GameObject is, an encapsulation of draw_rot with some extra cheese.
172
176
  # For example, we get automatic calls to draw/update with Chingu::GameObject, which usually is what you want.
@@ -193,6 +197,22 @@ Roughly 50 lines became 26 more powerful lines. (you can do @player.angle = 100
193
197
  If you've worked with Gosu for a while you're probably tired of passing around the window-parameter.
194
198
  Chingu solves this (as has many other developers) with a global variable $window. Yes, globals are bad, but in this case it kinda makes sense. It's used under the hood in various places.
195
199
 
200
+ The basic flow of Chingu::Window once show() is called is this (this is called one game iteration or game loop):
201
+
202
+ - Chingu::Window#draw() is called
203
+ -- draw() is called on game objects belonging to Chingu::Window
204
+ -- draw() is called on all game objects belonging to current game state
205
+
206
+ - Chingu::Window#update() is called
207
+ -- Input for Chingu::Window is processed
208
+ -- Input for all game objects belonging to Chingu::Window is processed
209
+ -- update() is called on all game objects belonging to Chingu::Window
210
+ -- Input for current game state is processed
211
+ -- Input for game objects belonging to current game state is processed
212
+ -- update() is called on all game objects belonging to current game state
213
+
214
+ ... the above is repeatet until game exists.
215
+
196
216
  === Chingu::GameObject
197
217
  This is our basic "game unit"-class, meaning most in game objects (players, enemies, bullets etc) should be inherited from Chingu::GameObject.
198
218
  The basic ideas behind it are:
@@ -473,19 +493,20 @@ The flow for a game object then becomes:
473
493
  There's a couple of traits included as default in Chingu:
474
494
 
475
495
  ==== Trait "timer"
476
- Adds timer functionallity to your game object
496
+ Adds timer functionality to your game object
477
497
  during(300) { @color = Color.new(0xFFFFFFFF) } # forces @color to white every update for 300 ms
478
498
  after(400) { self.destroy } # destroy object after 400 ms
479
499
  between(1000,2000) { self.rotate(10) } # starting after 1 second, call rotate(10) every update during 1 second
500
+ every(2000) { Sound["bleep.wav"].play } # play bleep.wav every 2 seconds
480
501
 
481
502
  ==== Trait "velocity"
482
- Adds variables velocity_x, velocity_y, acceleration_x, acceleration_y, max_velocity to game object.
503
+ Adds accessors velocity_x, velocity_y, acceleration_x, acceleration_y, max_velocity to game object.
483
504
  They modify x, y as you would expect. *speed / angle will come*
484
505
 
485
506
 
486
- ==== (IN DEVELOPMENT) Trait "effect"
487
- Adds ability to automaticly fade, rotate and scale game objects.
488
- * API isn't stabilized yet! *
507
+ ==== Trait "effect"
508
+ Adds accessors rotation_rate, fade_rate and scale_rate to game object.
509
+ They modify angle, alpha and factor_x/factor_y each update. Since this is pretty easy to do yourself this trait might be up for deprecation.
489
510
 
490
511
  ==== (IN DEVELOPMENT) Trait "collision_detection"
491
512
  Adds class and instance methods for basic collision detection.
@@ -510,7 +531,6 @@ Also provides new code for draw() which uses screen_x / screen_y instead of x /
510
531
 
511
532
 
512
533
 
513
-
514
534
  === Assets / Paths
515
535
 
516
536
  You might wonder why this is necessary in the straight Gosu example:
data/chingu.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{chingu}
5
- s.version = "0.5.8.2"
5
+ s.version = "0.5.9"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["ippa"]
9
- s.date = %q{2009-10-22}
9
+ s.date = %q{2009-10-25}
10
10
  s.description = %q{OpenGL accelerated 2D game framework for Ruby.
11
11
  Builds on the awesome Gosu (Ruby/C++) which provides all the core functionality.
12
12
  It adds simple yet powerful game states, prettier input handling, deployment safe asset-handling, a basic re-usable game object and automation of common task.}
@@ -10,10 +10,10 @@ include Chingu
10
10
  class Game < Chingu::Window
11
11
  def initialize
12
12
  super(640,400)
13
- self.input = {:esc => :exit}
14
- self.caption = "Example of Chingus HighScore class"
13
+ self.input = {:esc => :exit, :space => :remote_high_score, :a => :add}
14
+ self.caption = "Example of Chingus HighScore class. Press Space to go to fetch high scores remotely!"
15
15
 
16
- PulsatingText.create("HIGH SCORES", :x => $window.width/2, :y => 50, :size => 70)
16
+ @title = PulsatingText.create("HIGH SCORES", :x => $window.width/2, :y => 50, :size => 70)
17
17
 
18
18
  #
19
19
  # Load a list from disk, defaults to "high_score_list.yml"
@@ -25,29 +25,65 @@ class Game < Chingu::Window
25
25
  # Add some new high scores to the list. :name and :score are required but you can put whatever.
26
26
  # They will mix with the old scores, automatic default sorting on :score
27
27
  #
28
- 10.times { @high_score_list.add(:name => "NEW", :score => rand(10000)) }
28
+ 10.times do
29
+ data = {:name => "NEW", :score => rand(10000)}
30
+
31
+ position = @high_score_list.add(data)
32
+ if position
33
+ puts "#{data[:name]} - #{data[:score]} got position #{position}"
34
+ else
35
+ puts "#{data[:name]} - #{data[:score]} didn't make it"
36
+ end
37
+ end
38
+
39
+ create_text
40
+
41
+ # @high_score_list.save_to_file # Uncomment to save list to disk
42
+ end
43
+
44
+ def remote_high_score
45
+ game_objects.destroy_all
46
+
47
+ @title = PulsatingText.create("REMOTE WEBSERVICE HIGH SCORES", :x => $window.width/2, :y => 50, :size => 30)
48
+
49
+ #
50
+ # :game_id is the unique ID the game has on www.gamercv.com
51
+ # :user is the login for that specific game (set by owner)
52
+ # :password is the password for that specific game (set by owner)
53
+ #
54
+ # To read a high score list only :game_id is required
55
+ # To write to a high score list :user and :password is required as well
56
+ #
57
+ @high_score_list = HighScoreList.load_remote(:game_id => 1, :user => "chingu", :password => "chingu", :size => 10)
58
+ create_text
59
+ end
60
+
61
+ def add
62
+ data = {:name => "NEW", :score => 1600}
63
+ position = @high_score_list.add(data)
64
+ puts "Got position: #{position.to_s}"
65
+ create_text
66
+ end
67
+
68
+ def create_text
69
+ @score_texts ||= []
70
+ @score_texts.each { |text| text.destroy }
29
71
 
30
72
  #
31
73
  # Iterate through all high scores and create the visual represenation of it
32
74
  #
33
75
  @high_score_list.each_with_index do |high_score, index|
34
76
  y = index * 25 + 100
35
- Text.create(high_score[:name], :x => 200, :y => y, :size => 20)
36
- Text.create(high_score[:score], :x => 400, :y => y, :size => 20)
77
+ @score_texts << Text.create(high_score[:name], :x => 200, :y => y, :size => 20)
78
+ @score_texts << Text.create(high_score[:score], :x => 400, :y => y, :size => 20)
37
79
  end
38
80
 
39
81
  5.times do
40
82
  score = rand(20000)
41
- puts "position for #{score}: #{@high_score_list.position_by_score(score)}"
83
+ puts "position for possible score #{score}: #{@high_score_list.position_by_score(score)}"
42
84
  end
43
-
44
- # @high_score_list.save # Uncomment to save list to disk
45
85
  end
46
86
 
47
- def update
48
- super
49
- self.caption = "FPS #{$window.fps} - game objects: #{game_objects.size}"
50
- end
51
87
  end
52
88
 
53
89
  #
@@ -1,21 +1,23 @@
1
1
  ---
2
- - :name: ABC
3
- :score: 9260
4
- - :name: ABC
5
- :score: 9112
6
- - :name: ABC
7
- :score: 8660
8
- - :name: ABC
9
- :score: 8030
10
- - :name: ABC
11
- :score: 7802
12
- - :name: ABC
13
- :score: 6976
14
- - :name: ABC
15
- :score: 6718
16
- - :name: ABC
17
- :score: 6325
18
- - :name: ABC
19
- :score: 5632
20
- - :name: ABC
21
- :score: 4199
2
+ - :name: NEW
3
+ :score: 9971
4
+ - :name: NEW
5
+ :score: 9960
6
+ - :name: NEW
7
+ :score: 9912
8
+ - :name: NEW
9
+ :score: 9900
10
+ - :name: NEW
11
+ :score: 9885
12
+ - :name: NEW
13
+ :score: 9840
14
+ - :name: NEW
15
+ :score: 9839
16
+ - :name: NEW
17
+ :score: 9746
18
+ - :name: NEW
19
+ :score: 9742
20
+ - :name: NEW
21
+ :score: 9736
22
+ - :name: NEW
23
+ :score: 9706
data/lib/chingu.rb CHANGED
@@ -28,5 +28,5 @@ require File.join(CHINGU_ROOT,"chingu","require_all") # Thanks to http://github.
28
28
  require_all "#{CHINGU_ROOT}/chingu"
29
29
 
30
30
  module Chingu
31
- VERSION = "0.5.8.2"
31
+ VERSION = "0.5.9"
32
32
  end
@@ -47,13 +47,16 @@ module Chingu
47
47
  @y = options[:y] || 0
48
48
  @angle = options[:angle] || 0
49
49
 
50
- self.center = options[:center] || 0.5
50
+
51
51
  self.factor = options[:factor] || 1.0
52
- @center_x = options[:center_x] if options[:center_x]
53
- @center_y = options[:center_y] if options[:center_y]
54
52
  @factor_x = options[:factor_x] if options[:factor_x]
55
53
  @factor_y = options[:factor_y] if options[:factor_y]
56
-
54
+
55
+ self.center = options[:center] || 0.5
56
+ self.rotation_center(options[:rotation_center]) if options[:rotation_center]
57
+ @center_x = options[:center_x] if options[:center_x]
58
+ @center_y = options[:center_y] if options[:center_y]
59
+
57
60
  if options[:color].is_a?(Gosu::Color)
58
61
  @color = options[:color]
59
62
  else
@@ -25,7 +25,11 @@ module Chingu
25
25
  #
26
26
  # - Keeps a local YAML file with highscores, default highscores.yml in root game dir.
27
27
  # - Add, delete, clear highscores
28
- # - Iterate through highscores with simple Highscore#each
28
+ # - Iterate through highscores with simple HighScores#each
29
+ #
30
+ # Working with the high score list:
31
+ # ...as a local file requires gem 'yaml'
32
+ # ...as a remote gamercv.com resource requires gem 'crack' and 'rest_client'
29
33
  #
30
34
  class HighScoreList
31
35
  attr_reader :file
@@ -34,10 +38,16 @@ module Chingu
34
38
  # Create a new high score list with 0 entries
35
39
  #
36
40
  def initialize(options = {})
37
- require 'yaml'
38
41
  @file = options[:file] || "high_score_list.yml"
39
42
  @size = options[:size] || 100
40
43
  @sort_on = options[:sort_on] || :score
44
+
45
+ @user = options[:user]
46
+ @password = options[:password]
47
+ @game_id = options[:game_id]
48
+ @server = "http://api.gamercv.com"
49
+ @resource = nil
50
+
41
51
  @high_scores = Array.new
42
52
  end
43
53
 
@@ -46,25 +56,63 @@ module Chingu
46
56
  # If no :file is given, HighScoreList tries to load from file "high_score_list.yml"
47
57
  #
48
58
  def self.load(options = {})
59
+ require 'yaml'
49
60
  high_score_list = HighScoreList.new(options)
50
61
  high_score_list.load
51
62
  return high_score_list
52
63
  end
53
64
 
65
+ def self.load_remote(options = {})
66
+ high_score_list = HighScoreList.new(options)
67
+ high_score_list.load_remote
68
+ return high_score_list
69
+ end
70
+
54
71
  #
55
- # Add a new high score to list.
72
+ # Adda a new high score to the local file
56
73
  # 'data' is a hash of key/value-pairs that needs to contain at least the keys :name and :score
74
+ # Returns the position it got in the list, with 1 beeing the first positions
57
75
  #
58
76
  def add(data)
59
77
  raise "No :name value in high score!" if data[:name].nil?
60
78
  raise "No :score value in high score!" if data[:score].nil?
61
-
62
- @high_scores.push(data)
63
- @high_scores.sort! { |a, b| b[@sort_on] <=> a[@sort_on] }
64
- @high_scores = @high_scores[0..@size]
79
+ @resource ? add_remote(data) : add_local(data)
80
+ position_by_score(data[:score])
65
81
  end
66
82
  alias << add
67
83
 
84
+ #
85
+ # POSTs a new high score to the remote web service
86
+ #
87
+ def add_remote(data)
88
+ begin
89
+ @res = @resource.post({:high_score => data})
90
+ data = Crack::XML.parse(@res)
91
+ add_to_list(force_symbol_hash(data["high_score"]))
92
+ rescue RestClient::RequestFailed
93
+ puts "RequestFailed: couldn't add high score"
94
+ rescue RestClient::Unauthorized
95
+ puts "Unauthorized to add high score (check :user and :password arguments)"
96
+ end
97
+ end
98
+
99
+ #
100
+ # Adds a new high score to local file
101
+ # Returns the position it got in the list, with 1 beeing the first positions
102
+ #
103
+ def add_local(data)
104
+ add_to_list(force_symbol_hash(data))
105
+ save_to_file
106
+ end
107
+
108
+ #
109
+ # Returns the position of full data-hash data entry, used internally
110
+ #
111
+ def position_by_data(data)
112
+ position = @high_scores.rindex(data)
113
+ position += 1 if position
114
+ end
115
+
68
116
  #
69
117
  # Returns the position 'score' would get in among the high scores:
70
118
  # @high_score_list.position_by_score(999999999) # most likely returns 1 for the number one spot
@@ -79,6 +127,45 @@ module Chingu
79
127
  return nil
80
128
  end
81
129
 
130
+ #
131
+ # Load data from previously specified @file
132
+ #
133
+ def load
134
+ @high_scores = YAML.load_file(@file) if File.exists?(@file)
135
+ @high_scores = @high_scores[0..@size]
136
+ end
137
+
138
+ #
139
+ # Load data from remove web service.
140
+ # Under the hood, this is accomplished through a simple REST-interface
141
+ # The returned XML-data is converted into a simple Hash (@high_scores), which is also returned from this method.
142
+ #
143
+ def load_remote
144
+ raise "You need to specify a Game_id to load a remote high score list" unless defined?(@game_id)
145
+ raise "You need to specify a User to load a remote high score list" unless defined?(@user)
146
+ raise "You need to specify a Password to load a remote high score list" unless defined?(@password)
147
+
148
+ require 'rest_client'
149
+ require 'crack/xml'
150
+ @resource = RestClient::Resource.new "#{@server}/games/#{@game_id}/high_scores", :user => @user, :password => @password, :timeout => 20, :open_timeout => 5
151
+
152
+ @high_scores.clear
153
+ begin
154
+ res = @resource.get
155
+ data = Crack::XML.parse(res)
156
+ if data["high_scores"]
157
+ data["high_scores"].each do |high_score|
158
+ @high_scores.push(force_symbol_hash(high_score))
159
+ end
160
+ end
161
+ rescue RestClient::ResourceNotFound
162
+ puts "Couldn't find Resource, did you specify a correct :game_id ?"
163
+ end
164
+
165
+ @high_scores = @high_scores[0..@size]
166
+ return @high_scores
167
+ end
168
+
82
169
  #
83
170
  # Direct access to invidual high scores
84
171
  #
@@ -97,21 +184,31 @@ module Chingu
97
184
  @high_scores.each_with_index { |high_score, index| yield high_score, index }
98
185
  end
99
186
 
100
- #
101
- # Load data from previously specified @file
102
- #
103
- def load
104
- @high_scores = YAML.load_file(@file) if File.exists?(@file)
105
- end
106
-
107
187
  #
108
188
  # Save high score data into previously specified @file
109
189
  #
110
- def save
190
+ def save_to_file
191
+ require 'yaml'
111
192
  File.open(@file, 'w') do |out|
112
193
  YAML.dump(@high_scores, out)
113
194
  end
114
195
  end
196
+
197
+ private
115
198
 
199
+ def add_to_list(data)
200
+ @high_scores.push(data)
201
+ @high_scores.sort! { |a, b| b[@sort_on] <=> a[@sort_on] }
202
+ @high_scores = @high_scores[0..@size]
203
+ end
204
+
205
+ def force_symbol_hash(hash)
206
+ symbol_hash = {}
207
+ hash.each_pair do |key, value|
208
+ symbol_hash[key.to_sym] = value
209
+ end
210
+ return symbol_hash
211
+ end
212
+
116
213
  end
117
214
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chingu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.8.2
4
+ version: 0.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - ippa
@@ -30,7 +30,7 @@ cert_chain:
30
30
  hxtMlw==
31
31
  -----END CERTIFICATE-----
32
32
 
33
- date: 2009-10-22 00:00:00 +02:00
33
+ date: 2009-10-25 01:00:00 +02:00
34
34
  default_executable:
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
metadata.gz.sig CHANGED
Binary file