summaryrefslogtreecommitdiffhomepage
path: root/samples/14_sprite_limits/app/main.rb
blob: 9972cffef1060593bc29ea39d6a913e7eb75a0e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
=begin

 APIs listing that haven't been encountered in previous sample apps:

 - Instance variable (@): Used to give objects their own space to store data.
   Used in this sample app when the class data structure is chosen to assign
   star values, like the position, speed, size, color, etc. Check the
   initialize method inside of the StarClass class to see @ used.

 Reminders:

 - args.outputs.sprites: An array. The values generate a sprite.
   The parameters are [X, Y, WIDTH, HEIGHT, IMAGE PATH]
   For more information about sprites, go to mygame/documentation/05-sprites.md.

 - args.outputs.labels: An array. The values generate a label.
   The parameters are [X, Y, TEXT, SIZE, ALIGNMENT, RED, GREEN, BLUE, ALPHA, FONT STYLE]
   For more information about labels, go to mymgame/documentation/02-labels.md.

 - Symbol (:): Ruby object with a name and an internal ID. Symbols are useful
   because with a given symbol name, you can refer to the same object throughout
   a Ruby program.

 - args.state.new_entity: Used when we want to create a new object, like a sprite or button.
   For example, if we want to create a new button, we would declare it as a new entity and
   then define its properties. (Remember, you can use state to define ANY property and it will
   be retained across frames.)

 - to_s: Returns a string representation of an object.

 - to_i: Returns an integer representation of an object.

 - String interpolation: uses #{} syntax; everything between the #{ and the } is evaluated
   as Ruby code, and the placeholder is replaced with its corresponding value or result.

 - args.inputs.mouse.(x|y): The x and y location of the mouse.
   For more information about the mouse, go to mygame/documentation/07-mouse.md.

=end

# This sample app serves to show performance differences between using:
# a very flexible data structure (:entity),
# a less flexible but faster data structure (:strict),
# and the least flexible but fastest data structure (:class).

# If the user chooses the "class" data structure type, the StarClass will be used to assign star values
class StarClass
  attr_sprite
  attr_accessor :speed_x, :speed_y

  def initialize
    @x = -1280 * rand # random position on screen
    @y = -720 * rand
    @w = 15
    @h = 15
    @speed_x = 2 * rand + 1 # random speed
    @speed_y = 2 * rand + 1
    @r = 255
    @g = 255 * rand # random color
    @b = 255 * rand
    @a = 128
    @path = 'sprites/star.png'
  end
end

# Outputs sample app instructions onto console
# Provides acceptable command if user does not wish to enter their own input
# Calls methods needed to create and show stars
def tick args
  if Kernel.global_tick_count == 0
    args.gtk.console.show # shows console when the sample app initially opens
    puts "
================================================
                    HELLO!!!!
================================================

This sample app shows the performance differences between using
a very flexible data structure (:entity),
a less flexible but faster data structure (:strict),
and the least flexible but fastest data structure (:class).

To see the differences use the `reset_with SPRITE_COUNT, CATEGORY` method.

For example, the following invocations generate 100 sprites of each data structure type:

    reset_with 100, :entity
    reset_with 100, :strict
    reset_with 100, :class

and these commands generate 1k sprites of each data structure type:

    reset_with 1000, :entity
    reset_with 1000, :strict
    reset_with 1000, :class

================================================
"
    args.gtk.console.current_input_str = 'reset_with 1000, :entity' # default input for user
  end

  defaults args
  render_stars args
  move_stars args
  process_inputs args
end

# Sets default values, creates empty collection of stars
# Creates stars depending on whether user chooses the "entity", "strict", or "class" option
# by using an if/elsif statement
# Initialization happens only in first frame
def defaults args
  args.outputs.background_color = [0, 0, 0] # black background
  args.state.star_count ||= 10
  args.state.option ||= :class
  args.state.stars ||= args.state.star_count.map do # do the following to 10 stars
    r = nil # r starts off empty (given value later based on which data structure is chosen)
    if args.state.option == :entity # if the entity data structure is chosen
      r = args.state.new_entity(:star) do |star| # declares each star as new entity, sets properties
        star.x = -1280 * rand # random position
        star.y = -720 * rand
        star.speed_x = 2 * rand + 1 # random speed
        star.speed_y = 2 * rand + 1
        star.r = 255 # white color
        star.g = 255
        star.b = 255
        star.alpha = 128 # slightly transparent
        star.sprite = [star.x, star.y, 15, 15, 'sprites/star.png', 0, star.alpha, 255, 255 * rand, 255 * rand] # sets definition for star sprite (color is randomized)
      end
    elsif args.state.option == :strict # otherwise, if the strict data structure is chosen
      r = args.state.new_entity_strict(:star) do |star| # declares each star as new entity, sets properties
        star.x = -1280 * rand # random position
        star.y = -720 * rand
        star.speed_x = 2 * rand + 1 # random speed
        star.speed_y = 2 * rand + 1
        star.r = 255 # white
        star.g = 255
        star.b = 255
        star.alpha = 128 # slightly transparent
        star.sprite = [star.x, star.y, 15, 15, 'sprites/star.png', 0, star.alpha, 255, 255 * rand, 255 * rand] # sets definition for star sprite (color is randomized)
      end
    elsif args.state.option == :class # if the class data structure is chosen
      r = StarClass.new # uses StarClass to assign star values
    end
    r # returns r; value based on which part of the if statement above ran
  end
  args.state.stars ||= [] # initialized to empty array (if value of stars has not already been set)
end

# Used to output solids, sprites (specifically the stars), and labels on the screen
def render_stars args
  args.outputs.solids << [0, 0, 1280, 720] # sets black background

  # Outputs stars
  args.outputs.sprites << args.state.stars.map do |star| # outputs every star in the collection
    star.sprite
  end

  # Outputs (white) label with number of stars, type of data structure chosen,
  # and frames per second
  args.outputs.labels << [10, 30, "Count: #{args.state.star_count}, Type: #{args.state.option}, FPS: #{args.gtk.current_framerate.to_s.to_i}", 255, 255, 255, 80] # string interpolation
  # converts current framerate to a string, and then converts that result to an integer value
end

# Allows the stars to move across the screen
# Stars loop back around if they exceed the scope of the screen
def move_stars args
  args.state.stars.map! do |star| # for each star in the collection
    star.x = -200 * rand if star.x > 1500 # random x position if exceeds x value of 1500 (goes too far right)
    star.y = -200 * rand if star.y > 800 # random y position if exceeds y value fo 800 (goes too far up)
    star.x += star.speed_x # increments position by star's speed
    star.y += star.speed_y
    star.sprite.x = star.x # the sprite's position is the star's position
    star.sprite.y = star.y
    star
  end
end

# Creates and outputs a red border to surround the mouse
# Resets game if "r" key on keyboard is pressed
def process_inputs args
  # 50 is subtracted from x and y so the mouse can be in the center of red box
  mouse_border = [args.inputs.mouse.x - 50, args.inputs.mouse.y - 50, 100, 100, 255, 0, 0]
  args.outputs.borders << mouse_border
  $gtk.reset if args.inputs.keyboard.key_down.r
end

# Resets the game, and assigns the star_count and option values given by the user
def reset_with count, option
  $gtk.reset
  $gtk.args.state.option = option
  $gtk.args.state.star_count = count
end