Active = 1, -- Will be moving around or need other periodic updates
-- and should provide its own update function
Controllable = 2, -- Can be controlled in some way
+ HasSprite = 3,
}
+assets.PropertyFlag = PropertyFlag
function assets.integrate_object_layers(pmap)
for k,layer in pairs(pmap.layers) do
-- of a map will override the first position an object is drawn in (and worse).
for ok,ov in pairs(new_layer.objects) do
local object = assets.get_object(ov.name)
- if object then
+ if object and utils.flag_set(object.properties, PropertyFlag.HasSprite) then
object.image = love.graphics.newImage(object.path)
- pmap[ov.name] = {}
- -- Tiled does y values from the bottom of the sprite so pull up 1
- pmap[ov.name].vec = vector.new_xy(ov.x, ov.y - pmap.tileheight)
- pmap[ov.name].name = ov.name
end
+ pmap[ov.name] = {}
+ -- Tiled does y values from the bottom of the sprite so pull up 1
+ pmap[ov.name].vec = vector.new_xy(ov.x, ov.y - pmap.tileheight)
+ pmap[ov.name].name = ov.name
end
new_layer.draw = function(self)
-- If relevant, an Object asset's name should match an object as placed
-- in an Object layer of a Tiled map
assets.store_object('Player', {
- properties = (PropertyFlag.Active),
+ properties = bit.bor(PropertyFlag.Active, PropertyFlag.Controllable, PropertyFlag.HasSprite),
path = 'assets/sprites/gilgamesh.png',
vec = vector.new_xy(),
+ viewspace = vector.new_xy(),
update = function(self, dt)
end
})
control.keymap[render.ViewClass.Topdown] = {}
control.keymap[render.ViewClass.Sidescroll] = {}
-control.keymap[render.ViewClass.Topdown]['l'] = { heading = (math.pi / 2) * -0, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['k'] = { heading = (math.pi / 2) * -1, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['h'] = { heading = (math.pi / 2) * -2, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['j'] = { heading = (math.pi / 2) * -3, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['d'] = { heading = (math.pi / 2) * -0, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['w'] = { heading = (math.pi / 2) * -1, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['a'] = { heading = (math.pi / 2) * -2, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Topdown]['s'] = { heading = (math.pi / 2) * -3, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['l'] = { heading = utils.Headings.East, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['k'] = { heading = utils.Headings.North, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['h'] = { heading = utils.Headings.West, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['j'] = { heading = utils.Headings.South, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['d'] = { heading = utils.Headings.East, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['w'] = { heading = utils.Headings.North, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['a'] = { heading = utils.Headings.West, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Topdown]['s'] = { heading = utils.Headings.South, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Sidescroll]['l'] = { heading = (math.pi / 2) * -0, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Sidescroll]['h'] = { heading = (math.pi / 2) * -2, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Sidescroll]['a'] = { heading = (math.pi / 2) * -2, control = control.ControlType.Movement, }
-control.keymap[render.ViewClass.Sidescroll]['d'] = { heading = (math.pi / 2) * -0, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Sidescroll]['l'] = { heading = utils.Headings.East, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Sidescroll]['h'] = { heading = utils.Headings.West, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Sidescroll]['a'] = { heading = utils.Headings.West, control = control.ControlType.Movement, }
+control.keymap[render.ViewClass.Sidescroll]['d'] = { heading = utils.Headings.East, control = control.ControlType.Movement, }
control.keymap['global'] = {}
control.keymap['global']['q'] = {
last_color = { love.graphics.getColor() }
love.graphics.setColor(render.color.dark)
- love.graphics.print(IntroMessage, math.floor((conf.window.width/16) * 1), math.floor((conf.window.height/16) * 1))
+ local adjust = render.worldspace_to_viewspace(player.vec)
+ love.graphics.rectangle('line', adjust.x, adjust.y, 32, 32)
+ --love.graphics.print(IntroMessage, math.floor((conf.window.width/16) * 1), math.floor((conf.window.height/16) * 1))
love.graphics.setColor(last_color)
end
-- Direction vectors for each heading
local dx = math.floor(math.cos(value.heading) + 0.5)
local dy = math.floor(math.sin(value.heading) + 0.5)
+ -- Update the player's heading for use elsewhere
+ player_obj.vec.heading = value.heading
local target_tile_x = current_tile_x + dx
local target_tile_y = current_tile_y + dy
render.map.active_map = nil
-- A bounding box to mask rendering for the main scene.
--- e.g., anything outside this (or in?) should not be rendered.
--- I don't know if Love supports this but I can always just draw black boxes lol.
--- Look into love.graphics.stencil
+-- e.g., anything outside this should not be rendered.
render.viewport =
{
ox = 0,
ey = conf.window.height,
}
-render.activate_map = function(new_map_name)
+function render.activate_map(new_map_name)
local success = false
-
local new_map = assets.get_map(new_map_name)
if new_map then
success = true
render.map.active_map = new_map
render.active_viewclass = render.ViewClassData[new_map.properties.viewclass]
+ render.map.active_map.first_loop = true
-- Find all objects in the map we're switching to, and update their positional
-- info with the unique copy stored in each map.
object.vec = object_in_map.vec
if key == 'Player' then
render.map.topleft = render.map.active_camera(object)
+ elseif key == 'CameraFocus' then
+ render.map.topleft = render.map.active_camera(object)
end
end
end
return new_viewport
end
+-- Convert an absolute position in the map/gameworld
+-- to where it would show up in the viewport.
+function render.worldspace_to_viewspace(world_position)
+ local view_position = utils.shallow_copy(world_position)
+ local tile = {
+ w = render.map.active_map.tilewidth,
+ h = render.map.active_map.tileheight,
+ }
+
+ local offsets =
+ {
+ x = (render.viewport.ex * math.floor((render.map.scale * world_position.x) / render.viewport.ex)),
+ y = (render.viewport.ey * math.floor((render.map.scale * world_position.y) / render.viewport.ey)),
+ }
+ view_position.x = (render.map.scale * (world_position.x )) + render.viewport.ox - offsets.x
+ view_position.y = (render.map.scale * (world_position.y )) + render.viewport.oy - offsets.y
+
+ return view_position
+end
+
render.CameraClass = {
-- Constantly place the player in the dead center of the window
PlayerInMiddle = 1,
render.map.cameras = {}
render.map.cameras[render.CameraClass.PlayerInMiddle] =
function(focus, bounds)
+ if render.map.active_map.first_loop then
+ render.map.active_map.first_loop = false
+ end
+
local offsets = {}
- local new_txty =
+ local new_topleft =
{
x = (((conf.window.width / 2) / render.map.scale) - (focus.vec.x)),
y = (((conf.window.height / 2) / render.map.scale) - (focus.vec.y)),
}
- offsets.x = math.fmod(new_txty.x, (render.map.active_map.tilewidth))
- offsets.y = math.fmod(new_txty.y, (render.map.active_map.tileheight))
- new_txty.x = new_txty.x - offsets.x
- new_txty.y = new_txty.y - offsets.y
- return new_txty
+ offsets.x = math.fmod(new_topleft.x, (render.map.active_map.tilewidth))
+ offsets.y = math.fmod(new_topleft.y, (render.map.active_map.tileheight))
+ new_topleft.x = new_topleft.x - offsets.x
+ new_topleft.y = new_topleft.y - offsets.y
+
+ return new_topleft
end
render.map.cameras[render.CameraClass.NESFreeRoam] =
function(focus)
- -- temp code
- return focus.vec or { x = 0, y = 0 }
+ local tile = {
+ w = render.map.active_map.tilewidth * render.map.scale,
+ h = render.map.active_map.tileheight * render.map.scale,
+ }
+
+ -- On the first focusing of a map in this mode, find the map's CameraFocus object
+ -- and use that for our topleft
+ if render.map.active_map.first_loop then
+ render.map.active_map.first_loop = false
+ return
+ {
+ x = render.map.active_map['CameraFocus'].vec.x + (tile.w/2),
+ y = render.map.active_map['CameraFocus'].vec.y + (tile.h),
+ }
+ end
+
+ local new_topleft = render.map.topleft
+ local viewspace_focus = render.worldspace_to_viewspace(focus.vec)
+
+ if ((focus.vec.heading == utils.Headings.East) and viewspace_focus.x == render.viewport.ox) then
+ new_topleft.x = new_topleft.x - (render.viewport.ex / render.map.scale)
+ elseif ((focus.vec.heading == utils.Headings.West) and viewspace_focus.x == render.viewport.ex) then
+ new_topleft.x = new_topleft.x + (render.viewport.ex / render.map.scale)
+ elseif ((focus.vec.heading == utils.Headings.South) and viewspace_focus.y == render.viewport.oy) then
+ new_topleft.y = new_topleft.y - (render.viewport.ey / render.map.scale)
+ elseif ((focus.vec.heading == utils.Headings.North) and viewspace_focus.y == render.viewport.ey) then
+ new_topleft.y = new_topleft.y + (render.viewport.ey / render.map.scale)
+ end
+ return new_topleft
end
-render.map.active_camera = render.map.cameras[render.CameraClass.PlayerInMiddle]
+render.map.active_camera = render.map.cameras[render.CameraClass.NESFreeRoam]
return render
tilewidth = 16,
tileheight = 16,
nextlayerid = 7,
- nextobjectid = 13,
+ nextobjectid = 14,
properties = {
["viewclass"] = "topdown"
},
51, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
918, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
- 920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
- 921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
- 922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 746, 747, 748, 0, 0, 0, 0, 0, 0, 0, 0, 51,
+ 920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 746, 747, 748, 0, 0, 0, 0, 0, 0, 0, 0, 1,
923, 0, 0, 0, 0, 0, 0, 206, 2684354765, 1610612941, 2684354765, 1610612941, 2684354765, 2684354766, 0, 0, 0, 0, 795, 796, 797, 0, 0, 0, 0, 0, 0, 0, 0, 51,
924, 0, 0, 0, 0, 0, 0, 3221225677, 0, 0, 0, 0, 0, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
925, 0, 0, 0, 0, 0, 0, 205, 206, 1610612941, 2684354765, 1610612941, 2684354766, 3221225677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
gid = 515,
visible = true,
properties = {}
+ },
+ {
+ id = 13,
+ name = "CameraFocus",
+ type = "Meta",
+ shape = "point",
+ x = 0,
+ y = 0,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {}
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
-<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="left-up" width="30" height="20" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="13">
+<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="left-up" width="30" height="20" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="14">
<editorsettings>
<export target="test_1.lua" format="lua"/>
</editorsettings>
51,869,870,871,872,873,874,875,876,877,878,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,
918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,
919,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,
-920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,
-921,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,
-922,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,746,747,748,0,0,0,0,0,0,0,0,51,
+920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
+921,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
+922,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,746,747,748,0,0,0,0,0,0,0,0,1,
923,0,0,0,0,0,0,206,2684354765,1610612941,2684354765,1610612941,2684354765,2684354766,0,0,0,0,795,796,797,0,0,0,0,0,0,0,0,51,
924,0,0,0,0,0,0,3221225677,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,
925,0,0,0,0,0,0,205,206,1610612941,2684354765,1610612941,2684354766,3221225677,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,
</layer>
<objectgroup id="2" name="Object Layer 1">
<object id="11" name="Player" gid="515" x="16" y="32" width="16" height="16"/>
+ <object id="13" name="CameraFocus" type="Meta" x="0" y="0">
+ <point/>
+ </object>
</objectgroup>
</map>
local utils = {}
+utils.Headings =
+{
+ East = math.pi / 2 * -0,
+ North = math.pi / 2 * -1,
+ West = math.pi / 2 * -2,
+ South = math.pi / 2 * -3,
+}
+
function utils.flag_set(value, flag)
return (bit.band(value, flag) ~= 0)
end
+function utils.set_flag(value, flag)
+ return (bit.bor(value, flag))
+end
+
function utils.shallow_copy(t)
local t2 = {}
for k,v in pairs(t) do
return t2
end
-function utils.shallow_dump(t)
- if t then
- for k,v in pairs(t) do
- print(k..':', v)
+function utils.shallow_dump(delim, ...)
+ for vark,varv in pairs({...}) do
+ print(delim..vark..':')
+ for k,v in pairs(varv) do
+ print('\t'..k..':', v)
end
end
end
+function utils.outside_box(box, pos)
+ -- return a vector indicating which way pos went out of the box
+ return
+ {
+ x = (pos.x >= (box.ex) and 1 or (pos.x < (box.ox - 32) and -1 or 0)),
+ y = (pos.y >= (box.ey) and 1 or (pos.y < box.oy and -1 or 0)),
+ }
+end
+
return utils