chingu 0.5.8.2 → 0.5.9

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