register_input("Next_Tileset", {{"key", "v"}}) register_input("Prev_Tileset", {{"key", "c"}}) register_input("Tile_Brush", {{"key", "t"}}) register_input("Entity_Brush", {{"key", "e"}}) register_input("Delete", {{"key", "delete"}, {"key", "backspace"}}) local basic_entity_properties = { {"flip_h", false}, {"flip_v", false}, } local entity_definitions = {} function define_entity(name, tex_name, properties, spawner) table.insert(entity_definitions, name) entity_definitions[name] = { spawner = spawner, tex_name = tex_name, properties = properties, idx = #entity_definitions, } end register_comp("Room_Editor", function(ent) ent.room_editor = { -- Valid values are Tile, Entity -- TODO: -- * Prop (place stuff on top of tiles automatically) brush = "Tile", tile = 1, entity = "Muntik", entity_snap = true, selected_ent = -1, placed_entities = {}, } end) register_comp("Editor_Entity", function(ent, room_editor, ent_type, x, y) ent.x = x ent.y = y local entity_def = entity_definitions[ent_type] local properties = {} for _, property in ipairs(basic_entity_properties) do local name = property[1] local default = property[2] properties[name] = default end for _, property in ipairs(entity_def.properties) do local name = property[1] local default = property[2] properties[name] = default end ent.editor_dat = { type = ent_type, room_editor = room_editor, properties = properties, } end) local function get_selected_entity(room_editor) return room_editor.placed_entities[room_editor.selected_ent] end local function new_editor_entity(room_editor, ent_type, x, y) local ent = new_entity() add_comp(ent, "Editor_Entity", room_editor, ent_type, x, y) add_comp(ent, "Sprite", entity_definitions[ent_type].tex_name, {}) return ent end function draw_editor_entity_sys(ent) local editor_dat = ent.editor_dat local selected_ent = get_selected_entity(editor_dat.room_editor) if selected_ent == ent then -- show selected mhmm lg.rectangle("line", ent.x, ent.y, ent.sprite.width, ent.sprite.height) end end local property_ui = { ["number"] = function(name, editor_dat, property) im.layout({0.5, 1}) im.text(name) im.text(tostring(snap(editor_dat.properties[name], 0.01))) im.layout() editor_dat.properties[name] = im.slider( editor_dat.properties[name], property.min or 0, property.max or 1, property.step or 0.1 ) end, ["boolean"] = function(name, editor_dat, property) im.layout({0.25, 0.5, 1}) im.text(name) im.text(tostring(editor_dat.properties[name])) if im.button("Toggle") then editor_dat.properties[name] = not editor_dat.properties[name] end end, } local function property_list(ent, properties) local editor_dat = ent.editor_dat for _, property in ipairs(properties) do local name = property[1] local prop_type = type(property[2]) property_ui[prop_type](name, editor_dat, property) im.layout() end end function editor_entity_ui_sys(ent) local editor_dat = ent.editor_dat if editor_dat.room_editor.brush ~= "Entity" then return end local selected_ent = get_selected_entity(editor_dat.room_editor) if selected_ent == ent then local entity_def = entity_definitions[editor_dat.type] im.begin_window("Entity Properties", 190, 5, 180, 340, {}) im.text("Base Properties") im.separator() property_list(ent, basic_entity_properties) im.separator() im.text("Type Properties") im.separator() property_list(ent, entity_def.properties) im.end_window() end end local function get_snapped_to_grid(room_editor, x, y) if room_editor.entity_snap then return snap(x, TILESIZE), snap(y, TILESIZE) else -- Still snap to the pixel cause yes return round(x), round(y) end end local brushes = { ["Tile"] = function(room_editor) if is_input_pressed("Left_Click") then local scn = get_current_scene() assert(scn, "no scene set.") local mx, my = get_mouse_pos() local tx, ty = to_tile_coords(mx, my) set_tile(scn.tilemap, tx, ty, room_editor.tile) end if is_input_pressed("Right_Click") then local scn = get_current_scene() assert(scn, "no scene set.") local mx, my = get_mouse_pos() local tx, ty = to_tile_coords(mx, my) remove_tile(scn.tilemap, tx, ty) end end, ["Entity"] = function(room_editor) local mx, my = get_mouse_pos() if is_input_just_pressed("Left_Click") then -- first check if we're selecting an entity local selected = false for i, ent in ipairs(room_editor.placed_entities) do if point_in_rect( mx, my, ent.x, ent.y, ent.sprite.width, ent.sprite.height ) then room_editor.selected_ent = i selected = true break end end -- Place one frfr if not selected then mx, my = get_snapped_to_grid(room_editor, mx, my) local ent = new_editor_entity(room_editor, room_editor.entity, mx, my) table.insert(room_editor.placed_entities, ent) room_editor.selected_ent = #room_editor.placed_entities end end end } function tile_place_sys(ent) local room_editor = ent.room_editor if not im.has_focus() then brushes[room_editor.brush](room_editor) end if is_input_just_pressed("Next_Tileset") then room_editor.tile = math.min(room_editor.tile + 1, get_tileset_count()) end if is_input_just_pressed("Prev_Tileset") then room_editor.tile = math.max(room_editor.tile - 1, 1) end if is_input_just_pressed("Tile_Brush") then room_editor.brush = "Tile" end if is_input_just_pressed("Entity_Brush") then room_editor.brush = "Entity" end end function room_editor_ui_sys(ent) local room_editor = ent.room_editor im.begin_window("Room Editor", 5, 5, 180, 180, {}) im.text("Brushes") im.layout({0.1, 1}) im.text("t") if im.button("Tile") then room_editor.brush = "Tile" end im.text("e") if im.button("Entity") then room_editor.brush = "Entity" end im.layout() im.end_window() if room_editor.brush == "Tile" then im.begin_window("Tile Editor", 5, 190, 180, 340, {}) im.text("Tile: " .. tostring(room_editor.tile)) im.separator() im.layout({0.1, 0.6, 1}) for tileset_id=1, get_tileset_count() do local text = " " if tileset_id == room_editor.tile then text = "*" elseif tileset_id == room_editor.tile - 1 then text = "c" elseif tileset_id == room_editor.tile + 1 then text = "v" end im.text(text) if im.button("select") then room_editor.tile = tileset_id end im.image(TILE_TEX, get_tileset_quad(tileset_id)) end im.layout() im.end_window() elseif room_editor.brush == "Entity" then im.begin_window("Entity Editor", 5, 190, 180, 340, {}) im.layout({0.2, 1}) im.text(room_editor.entity_snap and "On" or "Off") if im.button("Position Snapping") then room_editor.entity_snap = not room_editor.entity_snap end im.layout({0.1, 0.6, 1}) for _, entity_name in ipairs(entity_definitions) do local entity_def = entity_definitions[entity_name] local text = " " if entity_name == room_editor.entity then text = "*" end im.text(text) if im.button("select") then room_editor.entity = entity_name end im.image(get_tex(entity_def.tex_name)) end im.layout() im.end_window() end end