pixelfaucet/src/game.cr
2022-01-24 22:03:49 -05:00

109 lines
2.7 KiB
Crystal

require "./lib_sdl"
require "./pixel"
require "./sprite"
module PF
abstract class Game
FPS_INTERVAL = 1.0
SHOW_FPS = true
property scale : Int32
property title : String
property running = true
property screen : Sprite
getter width : Int32
getter height : Int32
@viewport : Vector2(Int32)? = nil
delegate :draw_point, :draw_line, :scan_line, :draw_circle, :draw_triangle, :draw_rect, :draw_shape,
:fill_triangle, :fill_rect, :fill_circle, :fill_shape, to: @screen
@fps_lasttime : Float64 = Time.monotonic.total_milliseconds # the last recorded time.
@fps_current : UInt32 = 0 # the current FPS.
@fps_frames : UInt32 = 0 # frames passed since the last recorded fps.
@last_time : Float64 = Time.monotonic.total_milliseconds
def initialize(@width, @height, @scale = 1, @title = self.class.name,
flags = SDL::Renderer::Flags::ACCELERATED,
window_flags : SDL::Window::Flags = SDL::Window::Flags::SHOWN)
SDL.init(SDL::Init::VIDEO)
@window = SDL::Window.new(@title, @width * @scale, @height * @scale, flags: window_flags)
@renderer = SDL::Renderer.new(@window, flags: flags)
@renderer.scale = {@scale, @scale}
@screen = Sprite.new(@width, @height)
end
abstract def update(dt : Float64, event : SDL::Event)
abstract def draw
def width=(value : Int32)
@viewport = nil
@width = value
# TODO: Resize window
end
def height=(value : Int32)
@viewport = nil
@height = value
# TODO: Resize window
end
def viewport
@viewport ||= Vector[@width, @height]
end
def elapsed_time
Time.monotonic.total_milliseconds
end
def clear(r = 0, g = 0, b = 0)
@screen.fill(r, g, b)
end
def run!
loop do
case event = SDL::Event.poll
when SDL::Event::Quit
break
end
engine_update(event)
engine_draw
break unless @running
end
ensure
SDL.quit
end
private def engine_update(event)
et = elapsed_time
calculate_fps(et)
update((et - @last_time) / 1000.0, event)
@last_time = et
GC.collect
end
private def calculate_fps(et)
return unless SHOW_FPS
@fps_frames += 1
if @fps_lasttime < et - FPS_INTERVAL * 1000
@fps_lasttime = et
@fps_current = @fps_frames
@fps_frames = 0
@window.title = String.build { |io| io << @title << " - " << @fps_current << " fps" }
end
end
private def engine_draw
@screen.lock do
draw
end
@renderer.copy(@screen.surface)
@renderer.present
end
end
end