summaryrefslogtreecommitdiffhomepage
path: root/samples/09_controller_analog_usage_advanced_sprites/app/main.rb
diff options
context:
space:
mode:
Diffstat (limited to 'samples/09_controller_analog_usage_advanced_sprites/app/main.rb')
-rw-r--r--samples/09_controller_analog_usage_advanced_sprites/app/main.rb226
1 files changed, 226 insertions, 0 deletions
diff --git a/samples/09_controller_analog_usage_advanced_sprites/app/main.rb b/samples/09_controller_analog_usage_advanced_sprites/app/main.rb
new file mode 100644
index 0000000..c3f2d8f
--- /dev/null
+++ b/samples/09_controller_analog_usage_advanced_sprites/app/main.rb
@@ -0,0 +1,226 @@
+=begin
+ APIs listing that haven't been encountered in previous sample apps:
+
+ - merge: Returns a hash containing the contents of two original hashes.
+ Merge does not allow duplicate keys, so the value of a repeated key
+ will be overwritten.
+
+ For example, if we had two hashes
+ h1 = { "a" => 1, "b" => 2}
+ h2 = { "b" => 3, "c" => 3}
+ and we called the command
+ h1.merge(h2)
+ the result would the following hash
+ { "a" => 1, "b" => 3, "c" => 3}.
+
+ Reminders:
+
+ - Hashes: Collection of unique keys and their corresponding values. The value can be found
+ using their keys.
+ In this sample app, we're using a hash to create a sprite.
+
+ - args.outputs.sprites: An array. The values generate a sprite.
+ The parameters are [X, Y, WIDTH, HEIGHT, PATH, ANGLE, ALPHA, RED, GREEN, BLUE]
+ Before continuing with this sample app, it is HIGHLY recommended that you look
+ at mygame/documentation/05-sprites.md.
+
+ - args.inputs.keyboard.key_held.KEY: Determines if a key is being pressed.
+ For more information about the keyboard, go to mygame/documentation/06-keyboard.md.
+
+ - args.inputs.controller_one: Takes input from the controller based on what key is pressed.
+ For more information about the controller, go to mygame/documentation/08-controllers.md.
+
+ - num1.lesser(num2): Finds the lower value of the given options.
+
+=end
+
+# This sample app shows a car moving across the screen. It loops back around if it exceeds the dimensions of the screen,
+# and also can be moved in different directions through keyboard input from the user.
+
+# Calls the methods necessary for the game to run successfully.
+def tick args
+ default args
+ render args.grid, args.outputs, args.state
+ calc args.state
+ process_inputs args
+end
+
+# Sets default values for the car sprite
+# Initialization ||= only happens in the first frame
+def default args
+ args.state.sprite.width = 19
+ args.state.sprite.height = 10
+ args.state.sprite.scale = 4
+ args.state.max_speed = 5
+ args.state.x ||= 100
+ args.state.y ||= 100
+ args.state.speed ||= 1
+ args.state.angle ||= 0
+end
+
+# Outputs sprite onto screen
+def render grid, outputs, state
+ outputs.solids << [grid.rect, 70, 70, 70] # outputs gray background
+ outputs.sprites << [destination_rect(state), # sets first four parameters of car sprite
+ 'sprites/86.png', # image path of car
+ state.angle,
+ opacity, # transparency
+ saturation,
+ source_rect(state), # sprite sub division/tile (tile x, y, w, h)
+ false, false, # don't flip sprites
+ rotation_anchor]
+
+ # also look at the create_sprite helper method
+ #
+ # For example:
+ #
+ # dest = destination_rect(state)
+ # source = source_rect(state),
+ # outputs.sprites << create_sprite(
+ # 'sprites/86.png',
+ # x: dest.x,
+ # y: dest.y,
+ # w: dest.w,
+ # h: dest.h,
+ # angle: state.angle,
+ # source_x: source.x,
+ # source_y: source.y,
+ # source_w: source.w,
+ # source_h: source.h,
+ # flip_h: false,
+ # flip_v: false,
+ # rotation_anchor_x: 0.7,
+ # rotation_anchor_y: 0.5
+ # )
+end
+
+# Creates sprite by setting values inside of a hash
+def create_sprite path, options = {}
+ options = {
+
+ # dest x, y, w, h
+ x: 0,
+ y: 0,
+ w: 100,
+ h: 100,
+
+ # angle, rotation
+ angle: 0,
+ rotation_anchor_x: 0.5,
+ rotation_anchor_y: 0.5,
+
+ # color saturation (red, green, blue), transparency
+ r: 255,
+ g: 255,
+ b: 255,
+ a: 255,
+
+ # source x, y, width, height
+ source_x: 0,
+ source_y: 0,
+ source_w: -1,
+ source_h: -1,
+
+ # flip horiztonally, flip vertically
+ flip_h: false,
+ flip_v: false,
+
+ }.merge options
+
+ [
+ options[:x], options[:y], options[:w], options[:h], # dest rect keys
+ path,
+ options[:angle], options[:a], options[:r], options[:g], options[:b], # angle, color, alpha
+ options[:source_x], options[:source_y], options[:source_w], options[:source_h], # source rect keys
+ options[:flip_h], options[:flip_v], # flip
+ options[:rotation_anchor_x], options[:rotation_anchor_y], # rotation anchor
+ ] # hash keys contain corresponding values
+end
+
+# Calls the calc_pos and calc_wrap methods.
+def calc state
+ calc_pos state
+ calc_wrap state
+end
+
+# Changes sprite's position on screen
+# Vectors have magnitude and direction, so the incremented x and y values give the car direction
+def calc_pos state
+ state.x += state.angle.vector_x * state.speed # increments x by product of angle's x vector and speed
+ state.y += state.angle.vector_y * state.speed # increments y by product of angle's y vector and speed
+ state.speed *= 1.1 # scales speed up
+ state.speed = state.speed.lesser(state.max_speed) # speed is either current speed or max speed, whichever has a lesser value (ensures that the car doesn't go too fast or exceed the max speed)
+end
+
+# The screen's dimensions are 1280x720. If the car goes out of scope,
+# it loops back around on the screen.
+def calc_wrap state
+
+ # car returns to left side of screen if it disappears on right side of screen
+ # sprite.width refers to tile's size, which is multipled by scale (4) to make it bigger
+ state.x = -state.sprite.width * state.sprite.scale if state.x - 20 > 1280
+
+ # car wraps around to right side of screen if it disappears on the left side
+ state.x = 1280 if state.x + state.sprite.width * state.sprite.scale + 20 < 0
+
+ # car wraps around to bottom of screen if it disappears at the top of the screen
+ # if you subtract 520 pixels instead of 20 pixels, the car takes longer to reappear (try it!)
+ state.y = 0 if state.y - 20 > 720 # if 20 pixels less than car's y position is greater than vertical scope
+
+ # car wraps around to top of screen if it disappears at the bottom of the screen
+ state.y = 720 if state.y + state.sprite.height * state.sprite.scale + 20 < 0
+end
+
+# Changes angle of sprite based on user input from keyboard or controller
+def process_inputs args
+
+ # NOTE: increasing the angle doesn't mean that the car will continue to go
+ # in a specific direction. The angle is increasing, which means that if the
+ # left key was kept in the "down" state, the change in the angle would cause
+ # the car to go in a counter-clockwise direction and form a circle (360 degrees)
+ if args.inputs.keyboard.key_held.left # if left key is pressed
+ args.state.angle += 2 # car's angle is incremented by 2
+
+ # The same applies to decreasing the angle. If the right key was kept in the
+ # "down" state, the decreasing angle would cause the car to go in a clockwise
+ # direction and form a circle (360 degrees)
+ elsif args.inputs.keyboard.key_held.right # if right key is pressed
+ args.state.angle -= 2 # car's angle is decremented by 2
+
+ # Input from a controller can also change the angle of the car
+ elsif args.inputs.controller_one.left_analog_x_perc != 0
+ args.state.angle += 2 * args.inputs.controller_one.left_analog_x_perc * -1
+ end
+end
+
+# A sprite's center of rotation can be altered
+# Increasing either of these numbers would dramatically increase the
+# car's drift when it turns!
+def rotation_anchor
+ [0.7, 0.5]
+end
+
+# Sets opacity value of sprite to 255 so that it is not transparent at all
+# Change it to 0 and you won't be able to see the car sprite on the screen
+def opacity
+ 255
+end
+
+# Sets the color of the sprite to white.
+def saturation
+ [255, 255, 255]
+end
+
+# Sets definition of destination_rect (used to define the car sprite)
+def destination_rect state
+ [state.x, state.y,
+ state.sprite.width * state.sprite.scale, # multiplies by 4 to set size
+ state.sprite.height * state.sprite.scale]
+end
+
+# Portion of a sprite (a tile)
+# Sub division of sprite is denoted as a rectangle directly related to original size of .png
+# Tile is located at bottom left corner within a 19x10 pixel rectangle (based on sprite.width, sprite.height)
+def source_rect state
+ [0, 0, state.sprite.width, state.sprite.height]
+end