Update to render directly to surface

This commit is contained in:
Alex Clink 2021-11-25 12:27:34 -05:00
parent c3e21426e7
commit 3319e18747
12 changed files with 126 additions and 58 deletions

View file

@ -6,5 +6,5 @@ shards:
sdl: sdl:
git: https://github.com/ysbaddaden/sdl.cr.git git: https://github.com/ysbaddaden/sdl.cr.git
version: 0.1.0+git.commit.d2aa0fb2ee30e42fc8d046d2d00c03c76879cb17 version: 0.1.0+git.commit.0ded44711246feb3aa3ba28fea249c9b03be061b

View file

@ -6,6 +6,7 @@ class Asteroid < Sprite
include LxGame::VectorSprite include LxGame::VectorSprite
property size : Float64 = 1.0 property size : Float64 = 1.0
property color : Pixel = Pixel.new(128, 128, 128, 255)
def initialize def initialize
super super
@ -16,11 +17,8 @@ class Asteroid < Sprite
update_position(dt) update_position(dt)
end end
def draw(renderer) def draw(engine)
# renderer.draw_color = SDL::Color[0, 100, 100, 255]
# draw_radius(renderer)
frame = project_points(points: @frame, scale: Vector2.new(@size, @size)) frame = project_points(points: @frame, scale: Vector2.new(@size, @size))
renderer.draw_color = SDL::Color[128, 128, 128, 255] draw_frame(engine, frame, color)
draw_frame(renderer, frame)
end end
end end

View file

@ -8,22 +8,6 @@ require "./asteroid"
require "./bullet" require "./bullet"
require "./explosion" require "./explosion"
WIDTH = 600
HEIGHT = 400
SCALE = 2
module LxGame
def draw_point(renderer, x, y)
x = x % WIDTH
y = y % HEIGHT
x = WIDTH + x if x < 0
y = HEIGHT + y if y < 0
renderer.draw_point(x, y)
end
end
class Asteroids < Game class Asteroids < Game
@ship : Ship @ship : Ship
@asteroids = [] of Asteroid @asteroids = [] of Asteroid
@ -50,6 +34,17 @@ class Asteroids < Game
}) })
end end
# override to wrap the coordinates
def draw_point(x : Int32, y : Int32, pixel : Pixel, surface = @screen)
x = x % @width
y = y % @height
x = @width + x if x < 0
y = @height + y if y < 0
super(x, y, pixel, surface)
end
def generate_asteroids def generate_asteroids
center_size = Vector2.new(50.0, 50.0) center_size = Vector2.new(50.0, 50.0)
center_pos = Vector2.new((width.to_f / 2.0) - (center_size.x / 2.0), (height.to_f / 2.0) - (center_size.y / 2.0)) center_pos = Vector2.new((width.to_f / 2.0) - (center_size.x / 2.0), (height.to_f / 2.0) - (center_size.y / 2.0))
@ -192,15 +187,14 @@ class Asteroids < Game
end end
end end
def draw def draw(engine)
@renderer.draw_color = SDL::Color[0, 0, 0, 255] engine.clear
@renderer.clear @ship.draw(engine)
@ship.draw(@renderer) @bullets.each { |b| b.draw(engine) }
@bullets.each { |b| b.draw(@renderer) } @asteroids.each { |a| a.draw(engine) }
@asteroids.each { |a| a.draw(@renderer) } @explosions.each { |e| e.draw(engine) }
@explosions.each { |e| e.draw(@renderer) }
end end
end end
game = Asteroids.new(WIDTH, HEIGHT, SCALE) game = Asteroids.new(500, 400, 2)
game.run! game.run!

View file

@ -11,10 +11,10 @@ class Bullet < Sprite
update_position(dt) update_position(dt)
end end
def draw(renderer) def draw(engine)
brightness = ((4.0 - self.age) / 4.0) * 255 brightness = (((4.0 - self.age) / 4.0) * 255).to_u8
renderer.draw_color = SDL::Color[brightness, brightness, 0] color = Pixel.new(r: brightness, g: brightness, b: 0_u8)
renderer.draw_point(@position.x.to_i, @position.y.to_i) engine.draw_point(@position.x.to_i, @position.y.to_i, color)
end end
def collides_with?(other : VectorSprite) def collides_with?(other : VectorSprite)

View file

@ -12,6 +12,8 @@ module LxGame
property emit_angle : Float64 = 2 * Math::PI property emit_angle : Float64 = 2 * Math::PI
property size : Float64 = 0.0 property size : Float64 = 0.0
# property color : Pixel = Pixel.new
def generate_particle def generate_particle
Particle.build do |particle| Particle.build do |particle|
particle.position = @position particle.position = @position
@ -44,11 +46,9 @@ module LxGame
@particles.reject!(&.dead?) @particles.reject!(&.dead?)
end end
def draw(renderer : SDL::Renderer) def draw(engine)
renderer.draw_color = SDL::Color[255, 255, 0, 255]
@particles.each do |particle| @particles.each do |particle|
particle.draw(renderer) particle.draw(engine)
end end
end end
end end

View file

@ -1,3 +1,6 @@
require "./lib_sdl"
require "./pixel"
module LxGame module LxGame
abstract class Game abstract class Game
FPS_INTERVAL = 1.0 FPS_INTERVAL = 1.0
@ -15,18 +18,63 @@ module LxGame
def initialize(@width, @height, @scale = 1, @title = self.class.name) def initialize(@width, @height, @scale = 1, @title = self.class.name)
SDL.init(SDL::Init::VIDEO) SDL.init(SDL::Init::VIDEO)
@window = SDL::Window.new(@title, @width * @scale, @height * @scale) @window = SDL::Window.new(@title, @width * @scale, @height * @scale)
@renderer = SDL::Renderer.new(@window, flags: SDL::Renderer::Flags::SOFTWARE) @renderer = SDL::Renderer.new(@window, flags: SDL::Renderer::Flags::PRESENTVSYNC) # , flags: SDL::Renderer::Flags::SOFTWARE)
@renderer.scale = {@scale, @scale} @renderer.scale = {@scale, @scale}
@screen = SDL::Surface.new(LibSDL.create_rgb_surface(
flags: 0, width: @width, height: @height, depth: 32,
r_mask: 0xFF000000, g_mask: 0x00FF0000, b_mask: 0x0000FF00, a_mask: 0x000000FF
))
end end
abstract def update(dt : Float64) abstract def update(dt : Float64)
abstract def draw abstract def draw(engine : Game)
def elapsed_time def elapsed_time
Time.monotonic.total_milliseconds Time.monotonic.total_milliseconds
end end
def engine_update def clear(r = 0, g = 0, b = 0)
@screen.fill(0, 0, 0)
end
def draw_point(x : Int32, y : Int32, pixel : Pixel, surface = @screen)
target = surface.pixels + (y * surface.pitch) + (x * 4)
target.as(Pointer(UInt32)).value = pixel.format(surface.format)
end
# Draw a line using Bresenhams Algorithm
def draw_line(p1 : Vector2, p2 : Vector2, pixel : Pixel, surface = @screen)
return draw_line(p2, p1, pixel, surface) if p1.x > p2.x
x1, y1, x2, y2 = p1.x.to_i, p1.y.to_i, p2.x.to_i, p2.y.to_i
dx = (x2 - x1).abs
dy = -(y2 - y1).abs
sx = x1 < x2 ? 1 : -1
sy = y1 < y2 ? 1 : -1
d = dx + dy
x, y = x1, y1
loop do
draw_point(x, y, pixel, surface)
break if x == x2 && y == y2
d2 = d + d
if d2 >= dy
d += dy
x += sx
end
if d2 <= dx
d += dx
y += sy
end
end
end
private def engine_update
@fps_frames += 1 @fps_frames += 1
et = elapsed_time et = elapsed_time
@ -41,8 +89,12 @@ module LxGame
@last_time = et @last_time = et
end end
def engine_draw private def engine_draw
draw @screen.lock do
draw(self)
end
@renderer.copy(SDL::Texture.from(@screen, @renderer))
@renderer.present @renderer.present
end end

7
src/lx_game/lib_sdl.cr Normal file
View file

@ -0,0 +1,7 @@
module SDL
class Surface
def pixels
surface.pixels
end
end
end

View file

@ -11,11 +11,11 @@ module LxGame
update_position(dt) update_position(dt)
end end
def draw(renderer : SDL::Renderer) def draw(engine)
return if dead? return if dead?
brightness = ((@lifespan - @age) / @lifespan) * 255 brightness = ((((@lifespan - @age) / @lifespan) * 255) / 2).to_u8
renderer.draw_color = SDL::Color[brightness / 2, brightness / 2, brightness / 2] color = Pixel.new(r: brightness, g: brightness, b: brightness)
renderer.draw_point(@position.x.to_i, @position.y.to_i) engine.draw_point(@position.x.to_i, @position.y.to_i, color)
end end
end end
end end

16
src/lx_game/pixel.cr Normal file
View file

@ -0,0 +1,16 @@
module LxGame
struct Pixel
def self.random
new(rand(0_u8..0xFF_u8), rand(0_u8..0xFF_u8), rand(0_u8..0xFF_u8), 0xFF_u8)
end
property r, g, b, a
def initialize(@r : UInt8 = 255, @g : UInt8 = 255, @b : UInt8 = 255, @a : UInt8 = 255)
end
def format(format)
LibSDL.map_rgba(format, @r, @g, @b, @a)
end
end
end

View file

@ -31,6 +31,6 @@ module LxGame
end end
abstract def update(dt : Float64) abstract def update(dt : Float64)
abstract def draw(renderer : SDL::Renderer) abstract def draw(engine : Game)
end end
end end

View file

@ -55,17 +55,17 @@ module LxGame
end end
end end
def draw_frame(renderer : SDL::Renderer, frame = @frame) def draw_frame(engine : Game, frame = @frame, color : Pixel = Pixel.new)
0.upto(frame.size - 1) do |n| 0.upto(frame.size - 1) do |n|
draw_line(renderer, frame[n], frame[(n + 1) % frame.size]) engine.draw_line(frame[n], frame[(n + 1) % frame.size], color)
end end
end end
def draw_radius(renderer : SDL::Renderer, points = 30) def draw_radius(engine : Game, points = 30, color : Pixel = Pixel.new)
circle = self.class.generate_circle(points, average_radius).map do |point| circle = self.class.generate_circle(points, average_radius).map do |point|
point + @position point + @position
end end
draw_frame(renderer, frame: circle) draw_frame(engine, frame: circle, color: color)
end end
end end
end end

View file

@ -10,6 +10,7 @@ class Ship < Sprite
@r_emitter : Emitter @r_emitter : Emitter
@projected_points : Array(Vector2)? = nil @projected_points : Array(Vector2)? = nil
property blew_up : Bool = false property blew_up : Bool = false
@color = Pixel.new
def initialize def initialize
super super
@ -112,16 +113,16 @@ class Ship < Sprite
@r_emitter.rotation = @rotation + 1.5 @r_emitter.rotation = @rotation + 1.5
end end
def draw(renderer) def draw(engine)
return if @blew_up return if @blew_up
@emitter.draw(renderer) @emitter.draw(engine)
@emitter.emitting = false @emitter.emitting = false
@l_emitter.draw(renderer) @l_emitter.draw(engine)
@l_emitter.emitting = false @l_emitter.emitting = false
@r_emitter.draw(renderer) @r_emitter.draw(engine)
@r_emitter.emitting = false @r_emitter.emitting = false
renderer.draw_color = SDL::Color[255, 255, 255, 255] # renderer.draw_color = SDL::Color[255, 255, 255, 255]
draw_frame(renderer, projected_points) draw_frame(engine, projected_points, @color)
end end
end end