ObscureWorlds Libraries

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
StoneCrow
Party member
Posts: 199
Joined: Sat Apr 17, 2010 9:31 am
Location: Wales the land of leeks and leaks
Contact:

ObscureWorlds Libraries

Post by StoneCrow »

Image
Rather than cling onto them for my personal projects, would the community here be interested in the varied libraries I use for different projects accompanied with information on their use and creation?

I have libraries (if thats the right word) for: And a program framework that can load other games into itself like a hub viewable here, useful for project packs.
Everything would be released under zlib license.
Last edited by StoneCrow on Fri Apr 19, 2013 3:13 pm, edited 3 times in total.
Dull but sincere filler.
User avatar
markgo
Party member
Posts: 189
Joined: Sat Jan 05, 2013 12:21 am
Location: USA

Re: ObscureWorlds Libraries

Post by markgo »

Hell yea! I love free stuff.
User avatar
StoneCrow
Party member
Posts: 199
Joined: Sat Apr 17, 2010 9:31 am
Location: Wales the land of leeks and leaks
Contact:

Mouse Control

Post by StoneCrow »

Okay first library is my mouse control library, titled ow_control.

Code: Select all

--[[
LICENCE DETAILS: ZLIB LICENCE

Copyright (c) <2012> <Lewis Pearce>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
   distribution.
]]

-- HOLDS ALL GAME CONTROLS AND SOME FUNCTIONS RELATING TO THEM

-- interaction tables used by the menu system example
-- this is how i would use it myself
--[[
startuptable = { -- table key/name, for distinction, but tables without names can be fed straight into currenttable
	{x=100,y=70,w=600,h=80,action={"pre","rwrinfo"},},  -- position and size, with action telling what peice of code to use with it, action here has 2 entries the section and the actual action, this just lets me distinguish sections in the mouseAction function, but it can be coded to distinguish on table name/key instead
}
]]

-- currenttable to draw menu style interactions from
-- place in main.lua
-- more tables can be added to this but the detection functions return the last detection they make, allowing overlay menus to work without tinkery provided they are last in the currenttable list.
--currenttable = {startuptable}

-- click area detection functions for menu code
function nearestmenu(x,y)
	return nearestestui(x,y,currenttable)
end

function nearestestui(x,y,table)
	local id = null

	for i = 1,#table do
		for i,v in ipairs(table[i]) do
			if checkCollision(x,y,1,1,v.x,v.y,v.w,v.h) == true then
				id = {i,j,v.action}
			end
		end
	end
	return id
end

--input library for mousepresses
-- bashes the information straight through to the mouseAction below, but exceptions can be added so that it doesn't in some circumstances
function love.mousepressed(x,y,button)
	mouseAction(x,y,button)
end

function love.mousereleased(x,y,button)
	if button == "m" then
		mouseAction(x,y,5)
	end
end

-- HUD DETECTION CODE


--SUPERFUNCTION
--controls all of the mouse actions within the editor
--a bit cryptic but not to hard to understand
function mouseAction(x,y,act)
	-- this just gets what your currently clicking on from the tables your testing at the moment
	local n = nearestmenu(x,y)
	
	--NULL INPUT
	--stops it from crashing if theres nothing at click
	if n ~= null then
		if n[3][1] == "pre" then -- test one used as a distinction
			if n[3][2] == "rwrinfo" then -- test two used to work out the command
				-- STUFF TO DO HERE
			end
		end
	end
end
Above is the version that uses two entries in action to distinguish which part of mouseAction to go to, though it could use the key of the tables easily with minor modifications to mouseAction and nearestestui, I've just found that making sections independent from table saves alot of repeat code.
Would love any critique on this as I'm always expanding and simplifying its style, I'm aware that it is a very dry system that requires setting up for each project and page but I find this makes it more powerful just slower to enable and set up, though outside dependancies and a creator for the actual menutables could easily be written in.

This was developed over about 5 or 6 failed projects which required large and varied ability menus, huds and ui's. The original version was infact incredibly huge and about double the size of this due to no simplification or anything, I personally love this system and combined with a debug function shared below can be added and modified very very easily and rapidly.

The debug system just added to the bottom of love.graphics.draw(), you have to set the value "debug" as debug = true and create a font of size 11 called font11 to make it work, but it can be switched off by just setting debug to false.

Code: Select all

if debug then
	-- currenttable highlights
	love.graphics.setColor(255,255,255,100)
	love.graphics.setFont(font11)
	
	for i=1,#currenttable do
		for i,v in ipairs(currenttable[i]) do
			love.graphics.rectangle("fill",v.x,v.y,v.w,v.h)
		end
	end
	
	-- infopanel
	local temp = "FPS: "..love.timer.getFPS()..". x:"..mx..". y:"..my.."."
	if (mx+font11:getWidth(temp)) < love.graphics.getWidth() then
		love.graphics.setColor(0,30,100,150)
		love.graphics.rectangle("fill",mx+10,my-0,font11:getWidth(temp),11)
		love.graphics.setColor(200,255,255,255)
		love.graphics.rectangle("line",mx+10,my+0,font11:getWidth(temp),11)
		love.graphics.print(temp,mx+10,my+0)
	else
		love.graphics.setColor(0,30,100,150)
		love.graphics.rectangle("fill",mx-(font11:getWidth(temp)+10),my-0,font11:getWidth(temp),11)
		love.graphics.setColor(200,255,255,255)
		love.graphics.rectangle("line",mx-(font11:getWidth(temp)+10),my+0,font11:getWidth(temp),11)
		love.graphics.print(temp,mx-(font11:getWidth(temp)+10),my+0)
	end
	temp = nil
end
Finally here is an image of a menu created recently with this version of the system and with the debug module turned on.
ow_controlsystem.png
ow_controlsystem.png (235.03 KiB) Viewed 10077 times
It can also be viewed by pressing f1 in audiotree or f1/f2 in most of my programs.

If this is useful or interesting to anyone I will soon release the next block of code.
Last edited by StoneCrow on Fri Apr 19, 2013 3:14 pm, edited 1 time in total.
Dull but sincere filler.
User avatar
StoneCrow
Party member
Posts: 199
Joined: Sat Apr 17, 2010 9:31 am
Location: Wales the land of leeks and leaks
Contact:

Saving and loading

Post by StoneCrow »

Okay this one is alot more like a library.
OW_rope, it reads strings and burns them.

Code: Select all

--[[
LICENCE DETAILS: ZLIB LICENCE

Copyright (c) <2011> <Lewis Pearce>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
   distribution.
]]

---- EXAMPLE OF HOW TO USE THIS TABLE
----
---- require "ow_rope.lua"
---- ropeLoad("exampledirectory","examplesavefile")
----
---- and saving works like this
---- love.filesystem.write(savefilename,"name of table="..rope.burn(name of table))
---- although this seems basic, the rope.burn function can save almost every table without errors to lua or other txt formats, 
---- though they need a custom loader to load and run.
----
---- rope.load sets up your directory and loads a settings file. It can also be changed in much the same way mouseAction 
---- is meant to be changed for each  project, easily allowing you to add code calls based on the settings.
---- although only supporting saving in lua natively may leave programs open to the lua code security holes with downloaded save files,
---- its designed in such a way where the file should always be made on your computer and any downloaded savefiles are at the users risk

rope = {}

function rope.load(directory,savefile)
	math.randomseed(os.time())	
	
	-- you can put all the libraries your game loads here
	
	love.filesystem.setIdentity(directory)
	-- >>>
	if love.filesystem.exists(savefile) then 
		rope.read(savefile)
	elseif not love.filesystem.exists(savefile) then
	-- place what you want the default settings for this file here
		love.filesystem.mkdir("sandbox")
		love.filesystem.mkdir("challenge")
	
		settings = {
			fullscreen=false,
			premenu = true,
			colour = {{255,255,255},{0,0,0}},
			currentres = {800,600,1},
			canvases = true,
			volume = 0.3,
			subsettings = {
			showbranchpos = false
			}
		}
		--use this bit to save in other ways
		love.filesystem.write(savefile,"settings="..rope.burn(settings))
	end
	
	-- <<<
	-- if you need to set up actions after save/settings load do them here, eg, if settings.fullscreen then love.graphics.toggleFullscreen() end

end

-- tables must be compatible with rope.burn

function rope.burn(t)
	local data = {}
	if type(t) == "number" then
		return t
	elseif type(t) == "boolean" then
		if t then
			return "true"
		elseif not t then
			return "false"
		end
	elseif type(t) == "string" then
		return t
	elseif type(t) == "table" then
		local data = {}
		table.insert(data,"{\n")
		for k,v in pairs(t) do
			if type(k) ~= "number" and type(v) ~= "function" then
				local k_info = rope.burn(k)
				local v_info = rope.burn(v)
				if type(v) == "string" then
					v_info = '"'..v_info..'"'
				end
				table.insert(data,k_info)
				table.insert(data,"=")
				table.insert(data,v_info)
				table.insert(data,",\n")
				k_info,v_info = nil,nil
			elseif type(k) == "number" and type(v) == "table" then
				local v_info = rope.burn(v)
				table.insert(data,v_info)
				table.insert(data,",\n")
				v_info = nil
			elseif type(k) == "number" and type(v) == "number" then
				local v_info = rope.burn(v)
				table.insert(data,v_info)
				table.insert(data,",\n")
				v_info = nil
			elseif type(k) == "number" and type(v) == "boolean" then
				local v_info = rope.burn(v)
				table.insert(data,v_info)
				table.insert(data,",\n")
				v_info = nil
			elseif type(k) == "number" and type(v) == "string" then
				local v_info = rope.burn(v)
				table.insert(data,'"'..v_info..'"')
				table.insert(data,",\n")
				v_info = nil
			end
		end
		table.insert(data,"\n}")
		return table.concat(data)
	end
end

-- just the functions for loading the lua savefiles

function rope.read(item)
	love.filesystem.load(item)()
end

function rope.readandreturn(item)
	return love.filesystem.load(item)()
end
The code is designed to save in lua and read in lua and hasn't been tested for other formats though I imagine it could save tables to most formats but reading them would need a custom reader using rope.readandreturn.

This was developed the first time I needed a persistent setting file for a program, so the rope.load is designed purposely for that.
Though I've used rope.burn for lots of things after that. The ability to save strings and keys was added in later.

To check if the savefile saves correctly just go to the save directory and load it into a text editor, if saved correctly it should be easily readable and if saved in lua should load in and out of your program without issue.
A successful save setup should look like this:

Code: Select all

settings={
fullscreen=false,
premenu=true,
currentres={
800,
600,
4,
},
canvases=true,
subsettings={
showbranchpos=true,
},
volume=0.5,
colour={
{
60,
10,
10,
},
{
255,
90,
15,
},
},
}
I'm gonna wait till I get some feedback to post the next library :)
Last edited by StoneCrow on Fri Apr 19, 2013 3:15 pm, edited 2 times in total.
Dull but sincere filler.
User avatar
StoneCrow
Party member
Posts: 199
Joined: Sat Apr 17, 2010 9:31 am
Location: Wales the land of leeks and leaks
Contact:

Camera and useful functions

Post by StoneCrow »

Okay still no feedback.
Well here's the camera code

Code: Select all

--[[
LICENCE DETAILS: ZLIB LICENCE

Copyright (c) <2012> <Lewis Pearce>

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
   distribution.
]]

-- just load the table and keep the use of the name camera free
-- also uses mx and my as the mouse positions just add something that names them as the camera positions like mx = love.mouse.getX() in update

camera = {}

camera.mode = {"edges"}

camera.pos = {
	x = 0, --xpos
	y = 0, --ypos
	s = 1, --scale
}

-- just add this to love.update(dt)
function camera.update(dt)
	for i,v in ipairs(camera.mode) do
		if v == "edge" then
			if mx <= 10 and camera.pos.x > 0 then
				camera.pos.x = camera.pos.x - (100*dt)
			elseif mx >= settings.currentres[1]-10 then 
				camera.pos.x = camera.pos.x + (100*dt)
			end
		end
	end
end
This is a really simple section of code. I figured would just be more useful as an example to anyone of how to create and manage a camera function set, because writing it was something that threw me a year or two ago when I first wrote this kind of thing.

to enable it just follow the instructions in the code above and add the code below to love.draw()

Code: Select all

love.graphics.push()
	love.graphics.translate(-camera.pos.x,-camera.pos.y)
	love.graphics.scale(camera.pos.s,camera.pos.s)

-- graphics code affected by the translations

love.graphics.pop()

-- ui stuff or things that aren't affected
Finally I'll just post my functions collection file, this is just a few functions I find myself using over and over again in different projects. No license on this one so feel free to steal, some of it I've scavenged from all over the place myself.

Code: Select all

-- Enumerates the contents of a folder into a table, printf-able if you add the filetree variable

function recursiveEnumerate(folder, fileTree)
	local fileTree = fileTree or null
    local lfs = love.filesystem
    local filesTable = lfs.enumerate(folder)
	if fileTree == null then
		return filesTable
	else
		for i,v in ipairs(filesTable) do
			local file = folder.."/"..v
			if lfs.isFile(file) then
				fileTree = fileTree.."\n"..file
			elseif lfs.isDirectory(file) then
				fileTree = fileTree.."\n"..file.." (DIR)"
				fileTree = recursiveEnumerate(file, fileTree)
			end
		end
		return filetree
	end
end

-- SPLITS STRINGS INTO LETTERS OR WITH AN ITERATOR

function stringsplit(input,iterator)
	iterator = iterator or "."
	local output = {}
	for word in input:gmatch(iterator) do 
		table.insert(output, word)
	end
	return output
end

-- Y ORDERING

function ysort (a,b)
	return a.y>b.y
end

-- INVERT NUMBER
function math.invert(item,maxvalue) --item is the number and maxvalue is the top point of its range to invert it around
	return maxvalue - item
end

-- REVERSE NUMBER

function math.reverse(item)
	return -item
end

-- ROUNDING TO NEAREST

function roundtointeger(item)
	local integer, fraction = math.modf(item)
	if fraction >= 5 then
		integer = integer + 1
	end
	return integer
end

-- finds matching variables accross a table and puts their positions into a table
function findvar(data,pos,var)
	local output = {}
	for i,v in ipairs(data) do
		if v.pos == var then
			table.insert(output,i)
		end
	end
	return output
end

-- BOX COLLISIONS

-- this is from the love2d wiki
-- Collision detection function.
-- Checks if box1 and box2 overlap.
-- w and h mean width and height.
function checkCollision(box1x, box1y, box1w, box1h, box2x, box2y, box2w, box2h)
    if box1x > box2x + box2w - 1 or -- Is box1 on the right side of box2?
       box1y > box2y + box2h - 1 or -- Is box1 under box2?
       box2x > box1x + box1w - 1 or -- Is box2 on the right side of box1?
       box2y > box1y + box1h - 1    -- Is b2 under b1?
    then
        return false                -- No collision. Yay!
    else
        return true                 -- Yes collision. Ouch!
    end
end

-- SLIDER FUNCTION

-- moves 1 towards 2 over time
-- 3 is the speed
-- to use add the slider function to the update area
-- and define sliderinfo = {}
-- I.E sliderinfo = {{start,destination,speed}}

function slider(dt)
	if #sliderinfo > 0 then
		for i,v in ipairs(sliderinfo) do
			if v[1] ~= v[2] then
				if v[1] > v[2] then
					v[1] = v[1] - (v[3]*dt)
					if v[1] < v[2] then
						v[1] = v[2]
					end
				elseif v[1] < v[2] then
					v[1] = v[1] + (v[3]*dt)
					if v[1] > v[2] then
						v[1] = v[2]
					end
				end
			end
		end
	end
end

-- TEST IF SOMETHING IS ALREADY IN A TABLE
-- used to see if something should be added or not

function isintable(item,table,posi)
	local posi = posi or false
	local output = false
	if posi == false then
		for i,v in ipairs(table) do
			if v == item then
				output = true
			end
		end
	else
		for i,v in ipairs(table) do
			if v[posi] == item then
				output = true
			end
		end
	end
	posi = nil
	return output
end

-- same as above but returns its position
		
function whereintable(item,table)
	local output = null
	for i,v in ipairs(table) do
		if v == item then
			output = i
		end
	end
	return output
end
Thanks everyone who has had a look at this code :ultrahappy: !
Would love to hear about any of it, though the last file of functions is a bit outdated in places.
Dull but sincere filler.
DarthGrover
Prole
Posts: 16
Joined: Wed Feb 05, 2014 11:31 pm
Location: Ohio USA

Re: ObscureWorlds Libraries

Post by DarthGrover »

Thanks for the isintable library. Gregg
User avatar
StoneCrow
Party member
Posts: 199
Joined: Sat Apr 17, 2010 9:31 am
Location: Wales the land of leeks and leaks
Contact:

Re: ObscureWorlds Libraries

Post by StoneCrow »

Would anyone be interested in a breakdown of how my scenes/states library works?

I feel like I actually have a really comfortable and easy to use system here for loading different what I'm referring internally to as "states". If you have ever used Corona for mobiles you may recognise the use of this, as this is kind of my dream of how I wished that had worked.

In short each state has its own attached functions that correlate to love functions like update, draw or mouse, physically separating themselves and allowing different bits of your game to be easily loaded and dropped (think menu's, backgrounds, levels).

They also support:
rapid removal of themselves (not completely ironed out, full support but would be easy enough to do),

automatic fading of the entire state with minimum extra legwork within the state,

This is all possible by calling a "name" you gave the state when you loaded it (names cannot be the same for different states),

Setting their position in the draw order of states easily,
The main negative for some people might of course be the slight performance issue associated with the additional functions, but for the kind of games I write I haven't had a single performance issue yet and it's been the best thing I've designed for my work speed since I started programming.
Dull but sincere filler.
User avatar
Snuux
Prole
Posts: 49
Joined: Sun Dec 15, 2013 10:43 am
Location: Russia, Moskow
Contact:

Re: ObscureWorlds Libraries

Post by Snuux »

You use "table.insert" very often. And it's don't good. Read this, about lua optimizations: link
My library for easy saving Slib! Try this! Now you can encrypt your save!
- Drop of light LD#30
- OUTRANGE LD#31
(Sorry for my english. I learn it myself, and I don't have enough experience)
User avatar
StoneCrow
Party member
Posts: 199
Joined: Sat Apr 17, 2010 9:31 am
Location: Wales the land of leeks and leaks
Contact:

Re: ObscureWorlds Libraries

Post by StoneCrow »

Yeah I do, if I got to a point where a project was complex and slow enough I would begin to optimize. So far it hasn't been a problem for me on LÖVE.
Dull but sincere filler.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: ObscureWorlds Libraries

Post by Jasoco »

You just have to realize what table.insert and table.remove are doing. Using them a lot can become a bottleneck because they're essentially reordering entire tables every time you use them. Say you have a table with 1000 items and you remove number 5. What happens is the function now takes everything from 6 to 1000 and moves them all forward by 1 one at a time. And if you try to insert something back in at say slot 3, you are now moving 3-999 up 1 position in order to make room. It might not be a speed problem for small tables and small games but used a lot all that time can add up.

Removing or adding to the end will be faster than removing or adding to the beginning, but still.
Post Reply

Who is online

Users browsing this forum: No registered users and 42 guests