From cafa63e6ab5218e0980a6b775a1afed93c4d183c Mon Sep 17 00:00:00 2001 From: Luka Vandervelden Date: Sun, 4 Nov 2018 00:57:20 +0900 Subject: [PATCH] File splitting. --- src/main.cr | 135 ++++----------------------- src/naka.cr | 200 +--------------------------------------- src/naka/map.cr | 96 +++++++++++++++++++ src/naka/naka.cr | 198 +++++++++++++++++++++++++++++++++++++++ src/{ => naka}/noise.cr | 0 5 files changed, 316 insertions(+), 313 deletions(-) create mode 100644 src/naka/map.cr create mode 100644 src/naka/naka.cr rename src/{ => naka}/noise.cr (100%) diff --git a/src/main.cr b/src/main.cr index 0266cc1..e9cc553 100644 --- a/src/main.cr +++ b/src/main.cr @@ -3,99 +3,6 @@ require "json" require "./naka.cr" -class Map - @save_directory : String - getter generator - def initialize(@save_directory, &block : Proc(Tile, Int32, Int32, Tile?)) - Dir.mkdir_p @save_directory - - @generator = block - end - - class Object - getter type : String - def initialize(@type) - end - - def to_json(builder) - builder.object do - builder.field "type", @type - end - end - end - - class Tile < Array(Object) - def initialize(element) - initialize - - self << element - end - end - - CHUNK_SIZE = 32 - class Chunk - property tiles : Array(Array(Tile)) - getter x : Int32 - getter y : Int32 - - def initialize(@x, @y, map) - p "Creating Map::Chunk" - - @tiles = Array.new(CHUNK_SIZE) do |x| - x += @x * CHUNK_SIZE - - Array.new(CHUNK_SIZE) do |y| - y += @y * CHUNK_SIZE - - Tile.new(Object.new "stone").tap do |tile| - map.generator.call tile, x, y - end - end - end - end - - def to_json - { - :x => @x, - :y => @y, - :tiles => @tiles - }.to_json - end - - def get(x, y) - @tiles[x][y] - end - end - - @chunks = Hash(Int32, Hash(Int32, Chunk)).new - - def get_chunk(x, y) - chunks_list = @chunks[x]? - if chunks_list.nil? - chunks_list = Hash(Int32, Chunk).new - @chunks[x] = chunks_list - end - - chunk = chunks_list[y]? - if chunk.nil? - chunk = Chunk.new x, y, self - chunks_list[y] = chunk - - save chunk - end - - chunk - end - - def save(chunk : Chunk) - File.write "#{@save_directory}/chunk-#{chunk.x}-#{chunk.y}.json", chunk.to_json - end - - def get(x, y) - get_chunk(x / CHUNK_SIZE, y / CHUNK_SIZE).get(x % CHUNK_SIZE, y % CHUNK_SIZE) - end -end - class ImagesLoader getter grass : SDL::Texture getter stone : SDL::Texture @@ -131,7 +38,7 @@ images = ImagesLoader.new window connection_font = window.newFont "Connection.otf", 30.5 window.set_font connection_font -altitude_map = Naka::Noise2D.new.tap do |a| +altitude_noise = Naka::Noise2D.new.tap do |a| a.add_octave(32, 1) a.add_octave(16, 0.5) a.add_octave(8, 0.25) @@ -139,7 +46,7 @@ altitude_map = Naka::Noise2D.new.tap do |a| a.add_octave(2, 1/16) # wtf, too smol end -humidity_map = Naka::Noise2D.new.tap do |a| +humidity_noise = Naka::Noise2D.new.tap do |a| a.add_octave(64, 1) a.add_octave(32, 0.5) a.add_octave(16, 0.25) @@ -148,63 +55,61 @@ humidity_map = Naka::Noise2D.new.tap do |a| a.add_octave(2, 0.10) end -evil_map = Naka::Noise2D.new.tap do |a| +evil_noise = Naka::Noise2D.new.tap do |a| a.add_octave(48, 0.6) a.add_octave(32, 0.6) a.add_octave(16, 0.3) end -flowers_map = Naka::Noise2D.new(1, 1) +map = Naka::Map.new "map-test-01" do |tile, x, y| + altitude = altitude_noise.get(x, y) + 0.5 -map = Map.new "map-test-01" do |tile, x, y| - altitude = altitude_map.get(x, y) + 0.5 + humidity = humidity_noise.get(x, y) + 0.5 - humidity = humidity_map.get(x, y) + 0.5 - - evil = evil_map.get(x, y) + evil = evil_noise.get(x, y) if altitude < 0.25 - tile << Map::Object.new "sand" + tile << Naka::Map::Object.new "sand" if altitude < 0.175 - tile << Map::Object.new "water" + tile << Naka::Map::Object.new "water" else if humidity < 0.33 - tile << Map::Object.new "sand" + tile << Naka::Map::Object.new "sand" else - tile << Map::Object.new "dirt" + tile << Naka::Map::Object.new "dirt" end end elsif altitude < 0.75 - tile << Map::Object.new "dirt" + tile << Naka::Map::Object.new "dirt" if evil > 0.5 - tile << Map::Object.new "haunted" + tile << Naka::Map::Object.new "haunted" else - tile << Map::Object.new "grass" + tile << Naka::Map::Object.new "grass" end if altitude > 0.35 && altitude < 0.65 if humidity > 0.4 if humidity > 0.8 - tile << Map::Object.new "tree" + tile << Naka::Map::Object.new "tree" elsif humidity < 0.6 - tile << Map::Object.new "pine" + tile << Naka::Map::Object.new "pine" else if Random.rand(2) == 0 - tile << Map::Object.new "tree" + tile << Naka::Map::Object.new "tree" else - tile << Map::Object.new "pine" + tile << Naka::Map::Object.new "pine" end end else if Random.rand(10) == 0 - tile << Map::Object.new "flowers" + tile << Naka::Map::Object.new "flowers" end end end elsif altitude > 0.85 - tile << Map::Object.new "rocks" + tile << Naka::Map::Object.new "rocks" end end diff --git a/src/naka.cr b/src/naka.cr index febfb97..e050b8d 100644 --- a/src/naka.cr +++ b/src/naka.cr @@ -1,203 +1,7 @@ -require "sdl" -require "sdl/image" -require "sdl/ttf" - +# Not sure we’d even need that, buuut… class Naka end -require "./noise.cr" - -## Helper code comes here - -class Naka - def self.init - SDL.init SDL::Init::VIDEO - SDL::IMG.init SDL::IMG::Init::PNG - SDL::TTF.init - - at_exit { - SDL.quit - SDL::TTF.quit - } - end -end - -class Naka::Renderer < SDL::Renderer -end - -class Naka::Window - alias Flags = LibSDL::WindowFlags - alias Position = LibSDL::WindowPosition - - getter renderer - - @current_font : SDL::TTF::Font? = nil - - def initialize(title, width, height, - x : Position = Position::UNDEFINED, - y : Position = Position::UNDEFINED, - flags : Flags = Flags::SHOWN) - - @window = SDL::Window.new(title, width, height, x, y, flags) - @renderer = Naka::Renderer.new @window - - @renderer.draw_blend_mode = SDL::BlendMode::BLEND - end - - def newImage(file_path) : SDL::Texture - SDL::IMG.load(file_path, @renderer).tap do |texture| - texture.blend_mode = SDL::BlendMode::BLEND - end - end - - def newFont(file_path, font_size = 12) : SDL::TTF::Font - SDL::TTF::Font.new file_path, font_size - end - - # FIXME: We’ll probably want options for scaling, rotations, and so on. - def draw(texture : SDL::Texture, x : Int32, y : Int32, scale_x = 1, scale_y = 1) - @renderer.copy texture, - dstrect: SDL::Rect[x, y, (texture.width * scale_x).to_i, (texture.height * scale_y).to_i] - end - - def draw(surface : SDL::Surface, x : Int32, y : Int32) - @renderer.copy surface, - dstrect: SDL::Rect[x, y, surface.width, surface.height] - end - - def set_font(@current_font) - end - - # FIXME: - # - This only prints properly “solid” text. Shaded text (depixelated) - # would need some additional OpenGL manipulations. - # - This is very inefficient resources-wise. If we are willing to drop - # ligatures support (is it even supported in SDL::TTF?), we should - # build a textures atlas of all glyphs and use that to render text. - # - Alternatively, it may be worth it to let users generate a texture of - # some text and draw it, manually. - def print(text, x, y) - font = @current_font - - return if font.nil? - - surface = font.render_solid(text, SDL::Color[0, 0, 0, 255], @renderer.draw_color) - - draw surface, x, y - end -end - -class Naka::Timer - getter start - getter last_update - - def initialize - @start = Time.now - @last_update = @start - end - - def step - now = Time.now - - dt = now.epoch_ms - @last_update.epoch_ms - - @last_update = now - - dt - end -end - -class Naka::Event - class Quit - end - - class Draw - getter window : Naka::Window - - def initialize(@window) - end - end - - class Update - getter dt : Int64 - - def initialize(@dt) - end - end - - # FIXME: Split in KeyUp and KeyDown. - class KeyUp - getter key : LibSDL::Keycode - getter scan_code : LibSDL::Scancode - - def initialize(@key, @scan_code) - end - end - class KeyDown - getter key : LibSDL::Keycode - getter scan_code : LibSDL::Scancode - getter repeat : Bool - - def initialize(@key, @scan_code, @repeat) - end - end - - # FIXME: THIS MAIN LOOP IS **NOT** READY FOR PRODUCTION - # Update events are still missing, and both Draw and Update should - # be time-based. - # Why having a `window` parameter instead of making a Window#loop method? - # Because we may want to have a `windows` parameter in the future, although - # unlikely. But still possible. - def self.loop(window, &block) - max_fps = 60 - max_dt = 1000. / 60 - - timer = Naka::Timer.new - - renderer = window.renderer - - ::loop do - exit_requested = false - - while event = SDL::Event.poll - r_value = yield case event - when SDL::Event::Quit - Naka::Event::Quit.new - when SDL::Event::Keyboard - keysym = event.keysym - if event.type == LibSDL::EventType::KEYUP - Naka::Event::KeyUp.new keysym.sym, keysym.scancode - elsif event.type == LibSDL::EventType::KEYDOWN - Naka::Event::KeyDown.new keysym.sym, keysym.scancode, event.repeat != 0 - end - else # FIXME: Most event types may need proper Naka:: classes. - event - end - - if r_value == Naka::Event::Quit - exit_requested = true - break - end - end - - break if exit_requested - - dt = timer.step - - r_value = yield Naka::Event::Update.new dt - - break if r_value == Naka::Event::Quit - - renderer.draw_color = SDL::Color[255, 255, 255, 255] - renderer.clear - - yield Naka::Event::Draw.new window - - renderer.present - - sleep 0.001 - end - end -end +require "./naka/*" diff --git a/src/naka/map.cr b/src/naka/map.cr new file mode 100644 index 0000000..d6f1650 --- /dev/null +++ b/src/naka/map.cr @@ -0,0 +1,96 @@ + +require "json" + +class Naka::Map + @save_directory : String + getter generator + def initialize(@save_directory, &block : Proc(Tile, Int32, Int32, Tile?)) + Dir.mkdir_p @save_directory + + @generator = block + end + + class Object + getter type : String + def initialize(@type) + end + + def to_json(builder) + builder.object do + builder.field "type", @type + end + end + end + + class Tile < Array(Object) + def initialize(element) + initialize + + self << element + end + end + + CHUNK_SIZE = 32 + class Chunk + property tiles : Array(Array(Tile)) + getter x : Int32 + getter y : Int32 + + def initialize(@x, @y, map) + p "Creating Map::Chunk" + + @tiles = Array.new(CHUNK_SIZE) do |x| + x += @x * CHUNK_SIZE + + Array.new(CHUNK_SIZE) do |y| + y += @y * CHUNK_SIZE + + Tile.new(Object.new "stone").tap do |tile| + map.generator.call tile, x, y + end + end + end + end + + def to_json + { + :x => @x, + :y => @y, + :tiles => @tiles + }.to_json + end + + def get(x, y) + @tiles[x][y] + end + end + + @chunks = Hash(Int32, Hash(Int32, Chunk)).new + + def get_chunk(x, y) + chunks_list = @chunks[x]? + if chunks_list.nil? + chunks_list = Hash(Int32, Chunk).new + @chunks[x] = chunks_list + end + + chunk = chunks_list[y]? + if chunk.nil? + chunk = Chunk.new x, y, self + chunks_list[y] = chunk + + save chunk + end + + chunk + end + + def save(chunk : Chunk) + File.write "#{@save_directory}/chunk-#{chunk.x}-#{chunk.y}.json", chunk.to_json + end + + def get(x, y) + get_chunk(x / CHUNK_SIZE, y / CHUNK_SIZE).get(x % CHUNK_SIZE, y % CHUNK_SIZE) + end +end + diff --git a/src/naka/naka.cr b/src/naka/naka.cr new file mode 100644 index 0000000..e795f8d --- /dev/null +++ b/src/naka/naka.cr @@ -0,0 +1,198 @@ + +require "sdl" +require "sdl/image" +require "sdl/ttf" + +## Helper code comes here + +class Naka + def self.init + SDL.init SDL::Init::VIDEO + SDL::IMG.init SDL::IMG::Init::PNG + SDL::TTF.init + + at_exit { + SDL.quit + SDL::TTF.quit + } + end +end + +class Naka::Renderer < SDL::Renderer +end + +class Naka::Window + alias Flags = LibSDL::WindowFlags + alias Position = LibSDL::WindowPosition + + getter renderer + + @current_font : SDL::TTF::Font? = nil + + def initialize(title, width, height, + x : Position = Position::UNDEFINED, + y : Position = Position::UNDEFINED, + flags : Flags = Flags::SHOWN) + + @window = SDL::Window.new(title, width, height, x, y, flags) + @renderer = Naka::Renderer.new @window + + @renderer.draw_blend_mode = SDL::BlendMode::BLEND + end + + def newImage(file_path) : SDL::Texture + SDL::IMG.load(file_path, @renderer).tap do |texture| + texture.blend_mode = SDL::BlendMode::BLEND + end + end + + def newFont(file_path, font_size = 12) : SDL::TTF::Font + SDL::TTF::Font.new file_path, font_size + end + + # FIXME: We’ll probably want options for scaling, rotations, and so on. + def draw(texture : SDL::Texture, x : Int32, y : Int32, scale_x = 1, scale_y = 1) + @renderer.copy texture, + dstrect: SDL::Rect[x, y, (texture.width * scale_x).to_i, (texture.height * scale_y).to_i] + end + + def draw(surface : SDL::Surface, x : Int32, y : Int32) + @renderer.copy surface, + dstrect: SDL::Rect[x, y, surface.width, surface.height] + end + + def set_font(@current_font) + end + + # FIXME: + # - This only prints properly “solid” text. Shaded text (depixelated) + # would need some additional OpenGL manipulations. + # - This is very inefficient resources-wise. If we are willing to drop + # ligatures support (is it even supported in SDL::TTF?), we should + # build a textures atlas of all glyphs and use that to render text. + # - Alternatively, it may be worth it to let users generate a texture of + # some text and draw it, manually. + def print(text, x, y) + font = @current_font + + return if font.nil? + + surface = font.render_solid(text, SDL::Color[0, 0, 0, 255], @renderer.draw_color) + + draw surface, x, y + end +end + +class Naka::Timer + getter start + getter last_update + + def initialize + @start = Time.now + @last_update = @start + end + + def step + now = Time.now + + dt = now.epoch_ms - @last_update.epoch_ms + + @last_update = now + + dt + end +end + +class Naka::Event + class Quit + end + + class Draw + getter window : Naka::Window + + def initialize(@window) + end + end + + class Update + getter dt : Int64 + + def initialize(@dt) + end + end + + # FIXME: Split in KeyUp and KeyDown. + class KeyUp + getter key : LibSDL::Keycode + getter scan_code : LibSDL::Scancode + + def initialize(@key, @scan_code) + end + end + class KeyDown + getter key : LibSDL::Keycode + getter scan_code : LibSDL::Scancode + getter repeat : Bool + + def initialize(@key, @scan_code, @repeat) + end + end + + # FIXME: THIS MAIN LOOP IS **NOT** READY FOR PRODUCTION + # Update events are still missing, and both Draw and Update should + # be time-based. + # Why having a `window` parameter instead of making a Window#loop method? + # Because we may want to have a `windows` parameter in the future, although + # unlikely. But still possible. + def self.loop(window, &block) + max_fps = 60 + max_dt = 1000. / 60 + + timer = Naka::Timer.new + + renderer = window.renderer + + ::loop do + exit_requested = false + + while event = SDL::Event.poll + r_value = yield case event + when SDL::Event::Quit + Naka::Event::Quit.new + when SDL::Event::Keyboard + keysym = event.keysym + if event.type == LibSDL::EventType::KEYUP + Naka::Event::KeyUp.new keysym.sym, keysym.scancode + elsif event.type == LibSDL::EventType::KEYDOWN + Naka::Event::KeyDown.new keysym.sym, keysym.scancode, event.repeat != 0 + end + else # FIXME: Most event types may need proper Naka:: classes. + event + end + + if r_value == Naka::Event::Quit + exit_requested = true + break + end + end + + break if exit_requested + + dt = timer.step + + r_value = yield Naka::Event::Update.new dt + + break if r_value == Naka::Event::Quit + + renderer.draw_color = SDL::Color[255, 255, 255, 255] + renderer.clear + + yield Naka::Event::Draw.new window + + renderer.present + + sleep 0.001 + end + end +end + diff --git a/src/noise.cr b/src/naka/noise.cr similarity index 100% rename from src/noise.cr rename to src/naka/noise.cr