Movement Example

require 'gosu'
require './ball.rb'

class MovementExample < Gosu::Window
	def initialize
		super 640, 480
		self.caption = "Movement Example"
		img = Gosu::Image.new("./ball.png")
		@ball = Ball.new(img, self.width/2, self.height/2, 0)
	end

	def draw
		@ball.draw
	end

	def update
		timeElapsed = self.update_interval / 1000	#Elapsed time in seconds
		@ball.update(self, timeElapsed)
	end 
end

window = MovementExample.new.show

This snippet shows how to create a moving thing in Gosu. In it, Window acts as the conductor which tells the other things in our game (i.e. @ball) what to do and when using all three of the primary Window methods:

initialize directs the game setup (although it delegates some of the ball specifics to the Ball class’ own initialize method.

draw is called every frame and redraws the screen (again delegating the specifics to the ball).

update is also called every frame similar to draw, but there is one additional element- on line 17 we call Window#update_interval to figure out how much time has elapsed since that method was last called. Gosu gives us the number of miliseconds, so we divide it by 1000 to convert it to seconds (which is conceptually easier to deal with for the rest of the game logic).

The second part of this snippet is the Ball class which has the movement logic:

class Ball
	def initialize(img, x, y, angle)
		@img = img
		@x = x
		@y = y
		@angle = angle

		@velocityX = 25 + rand(150)
		@velocityY = 25 + rand(150)
		@velocityA = 45 + rand(15) # Angular Velocity
	end

	def draw
		@img.draw_rot( @x, @y, 0, @angle )
	end

	# Assumes 'delta' is measured in seconds
	def update(window, delta)
		# Movement logic
		@angle += @velocityA * delta
		@x += @velocityX * delta
		@y += @velocityY * delta

		# Collision Logic
		if @y - @img.height/2 < 0 or @y + @img.height/2 > window.height then
			@velocityY *= -1
		end
		if @x - @img.width/2 < 0 or @x + @img.width/2 > window.width then
			@velocityX *= -1
		end
	end
end

Notice how it mirrors the same three methods of the Window class. initialize and draw are relatively straightforward, but update has one item of interest. Notice on lines 20-22 that every frame we are not just adding the ball’s velocity (speed) to its position, but we’re scaling the speed based on how much time has elapsed. You can think of it this way: @velocityX is measured in pixels/second, so multiplying it by delta seconds keeps us moving at a steady rate regardless of how much time has elapsed between frames.