notnullgames / tiled-kaboom

Load maps made in Tiled into Kaboom!
https://notnullgames.github.io/tiled-kaboom/
19 stars 3 forks source link

option to load specific layers - for ysort tilemap problem #12

Closed blurymind closed 3 years ago

blurymind commented 3 years ago

How does one do y-sort with this extension? If I want the player/enemies/npc to be behind a tile, based on their y position?

konsumer commented 3 years ago

This was something I personally battled with, with love2d & sti! I never really got a workable solution I was happy with. For love, I just kinda gave up, and just added (invisible) collisions that would keep the player out of the y-fighing zone (put some layers only over, and other layers only under, then block the player sprite from getting into the places that make it look bad.) It sounds like a terrible solution, but a lot of classic games were made this way, and it actually felt ok. Godot has a great implementation, which is a nice example of how it should work, but not super-helpful, otherwise. This library just uses regular kaboom maps, so it may be a better question in their forums. map.levels has all your tilemap data in it (after decompressing and parsing the tiled map) and should be helpful for saying "what tiles overlap the player?"

You'll notice in the demo-code I don't really try to lock people into any particular path:

const { sprites, levels, key } = await k.loadTiledMap(YOUR_MAP_OBJECT)
for (let level of levels) {
  k.addLevel(level, { width: 32, height: 32, ...key })
}

I imagine you could render all below the player, figure out what is over/under by Y, and render over player in a few passes.

You can see my troubles with it, as a general programming issue in love here complete with links to resources & image illustrations, but all the code is in lua. My partial solution to that problem was here, but I never got it working how I want.

blurymind commented 3 years ago

would be cool if we had a minimal demo project right here that uses this extension and solves this very issue!

blurymind commented 3 years ago

The current example demo project doesnt work - you get a black page with some 404 errors in console.

In the source code- say that player is a part of the tilemap data somehow https://github.com/notnullgames/tiled-kaboom/blob/main/index.html#L60 can the player be y sorted?

Meaning: If player.y < object.y => draw player behind it, else draw player in front of it At this point the player and object origins are important - are they at the feet of the sprites or at their middle.If its the later - that wont work either - it needs to account for origin position being where the object actually touches the ground

konsumer commented 3 years ago

would be cool if we had a minimal demo project right here that uses this extension and solves this very issue!

Yeh! You should make one. I have a demo for the functionality of this library, but your specific usecase isn't something I'm personally trying to do with kaboom. Feel free to use this lib in your thing, and I can link to it in the README.

The current example demo project doesnt work - you get a black page with some 404 errors in console.

Hmm. Seems like my demo broke due to changes on kaboom. I updated to use their current url, and it seems like it broke how levels work. I may not have time to fix it right now, but I will take a look.

I'm not sure I follow the other stuff you are saying. Sounds like things you could figure out if you make your own demo and play around with it a bit, but I'm not sure I fully understand what you are asking.

blurymind commented 3 years ago

thanks for having another look at the demo. It is still broken btw image

konsumer commented 3 years ago

It is still broken btw

Yep, that is what I mentioned above.

konsumer commented 3 years ago

This really should be a separate issue, but I updated demo and published tiled-kaboom@0.0.12. They changed how addLevel works, but it was a simple enough fix.

blurymind commented 3 years ago

The demo has a great use case of the waterfall and is console logging the player although no player sprite is rendered anywhere.

Makes me wonder what needs to be done to add a top down movement and show a player sprite. Maybe I need to edit the tiled file first to give the player object a sprite?

konsumer commented 3 years ago

Here are some basic pointers to help you figure out Y-sorting, or at least get started on it, but it's definitely outside of the scope of this library.

This thing is meant to give you the setup you need to implement your own map logic. It just handles the boring stuff, like turning a compressed tiled map into a series of text-based layers that can be used in kaboom, like any other map layer.

Here are the bits I think you will need to figure it out, though:

object layer & player

This is pretty much straight from the demo:

// get all objects on layer called "Objects"
const { objects } = map.layers.find(l => l.name === 'Objects')

// I have an object named "player" I want info about in my map
const player = objects.find(o => o.name === 'player')

// put props in regular object shape
const props = player.properties.reduce((a, v) => ({ ...a, [v.name]: v.value }), {})

console.log('OBJECTS', { objects, player, props })

in player you will see there is a bunch of good stuff, like x, y, and height and width. All this is full-map oriented, so in my demo-map it's 128,64 meaning it's that many pixels from the map's origin (where the grid starts in tiled.)

Here you can see the grid in tiled, and how it's about that many pixels from the edges (each square is 32 pixels, so like 4,2 squares)

Screen Shot 2021-10-13 at 4 22 42 AM

You also want to note what layers can z-fight with your player. basically things above or below. There are several ways you could mark this (layer props, by layer-name, etc) but lets just say you put all the things that can z-fight on a single layer called "Objects" as I did in demo. So some layers are over, and some are under "Objects".

So basically, you will need to work out what objects are occupying the same space, and put them over/under each other based on their size/position.

The more I look at it, the less I am sure kaboom can even do stuff like Y-sorting, or even simple "this tile is over the player", but I'm really not an expert. Again, it may help to go ask this in a kaboom forums. The map layers that I am outputting are identical to what they have here, so if it's possible they should be able to help.

blurymind commented 3 years ago

my idea for this is to update the demo itself, not the library :)

For the library,it would be nice if the waterfall was animated, but there is another ticket for that

blurymind commented 3 years ago

If the player/npc is a part of the tilemap too, shouldnt pixi-tilemap handle the z-sorting?

konsumer commented 3 years ago

my idea for this is to update the demo itself, not the library :)

I don't want to complicate the demo with Y-sorting. It's specific to your application, and not helpful for "here is how to use my plugin." Like I said, I am happy to link to a demo if you want to make one.

If the player/npc is a part of the tilemap too, shouldnt pixi-tilemap handle the z-sorting?

I think you are thinking of another project 😊. How things in your game interact, even if based on a tiled map, is definitely outside of the scope of a tiled-loader library in general, so I would say "no" here, and it's probably also true with pixi-tilemap.

konsumer commented 3 years ago

For the library,it would be nice if the waterfall was animated, but there is another ticket for that

Yeh, I made #7 for that. My time is pretty limited, and I don't use kaboom too much (I've been into raylib, in C lately) so I'll happily accept a PR if you want to implement that.

konsumer commented 3 years ago

The demo has a great use case of the waterfall and is console logging the player although no player sprite is rendered anywhere.

Yeh, I added the waterfall to show "background animations" whenever that is implemented.

Makes me wonder what needs to be done to add a top down movement and show a player sprite. Maybe I need to edit the tiled file first to give the player object a sprite?

You could, I guess, but maybe you are conflating 2 parts of the problem. Like there is an object-layer that tracks where the player should start. You can use that info to load a sprite in the regular kaboom way and work out the Y-sorting with those extra sprites you add. It currently doesn't do anything with tiled objects other than just put them in a big data-array, which you can use in your own thing to figure out how to make it work like you want (as I show above, and in the demo.)

The tilemap could be considered just the "background layers" or you could do something different than add them all in a loop, like sandwich your sprites in between some layers (even using order in the layer info.)

blurymind commented 3 years ago

One way to achieve this could be by loading two tilemap objects. One for the bg layer and one for the foreground layer. The foreground tilemap could be the thing the player moves in front or behind based on y.

One thing this extension could do to help this is an option to allow loading a specific tilemap layer rather than all the layers. I did that for my implementation in gdevelop btw

On Wed, 13 Oct 2021, 15:18 David Konsumer, @.***> wrote:

The demo has a great use case of the waterfall and is console logging the player although no player sprite is rendered anywhere.

Yeh, I added the waterfall to show "background animations" whenever that is implemented.

Makes me wonder what needs to be done to add a top down movement and show a player sprite. Maybe I need to edit the tiled file first to give the player object a sprite?

You could, I guess, but maybe you are conflating 2 parts of the problem. Like there is an object-layer that tracks where the player should start. You can use that info to load a sprite in the regular kaboom way and work out the Y-sorting with those extra sprites you add. It currently doesn't do anything with tiled objects other than just put them in a big data-array, which you can use in your own thing to figure out how to make it work like you want (as I show above, and in the demo.)

The tilemap could be considered just the "background layers" or you could do something different than add them all in a loop, like sandwich your sprites in between some layers (even using order in the layer info.)

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/notnullgames/tiled-kaboom/issues/12#issuecomment-942244839, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABRRWVJYLQYZDZZVV2KMPJLUGV2K7ANCNFSM5FXRVDTA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

konsumer commented 3 years ago

One thing this extension could do to help this is an option to allow loading a specific tilemap layer rather than all the layers.

I do that:

for (let level of levels) {
  addLevel(level, { width: 32, height: 32, ...key })
}

is a loop, but you can add them however you want. I leave it completely up to you. mapObj has more info that came from the map, if you want to do it some other way.

Let's talk in more concrete terms. Say you have a map with 3 layer "under", and 3 layers "over":

// add "under"
for (let l in levels) {
  if (l < 3) {
    const level = levels[l]
    addLevel(level, { width: 32, height: 32, ...key })
  }
}

// do "in the middle stuff" here, for example add all objects with a sprite property:
for (const object of objects) {
  // get props in nicer object
  const props = object.properties.reduce((a, v) => ({ ...a, [v.name]: v.value }), {})

  // must have "sprite" prop to use a sprite
  if (props.sprite) {
    const newthing = [
      sprite(props.sprite),
      pos(object.x + offsetx, object.y + offsety)
    ]
    // do more with props here, if you like
    const mapObject = k.add(newthing)
  }
}

// add "over"
for (let l in levels) {
  if (l > 3) {
    const level = levels[l]
    addLevel(level, { width: 32, height: 32, ...key })
  }
}

I did that for my implementation in gdevelop btw

Is this yours? I have never used gdevelop, so I can't really evaluate how that works.

I give you the tools to make it work however you want, sort of like how kaboom does things. Any problems you have with what this library does are honestly problems with kaboom's map system, as it's a very thin wrapper around that. I made it because I had tiled maps, and I didn't want to hand-draw them again, with ascii.

konsumer commented 3 years ago

the above sprite code would load a sprite named "player" that looks like this, and put it in the right position:

Screen Shot 2021-10-13 at 6 51 22 AM
konsumer commented 3 years ago

My criteria of >3 or <3 is just an arbitrary example. You can use the map data to do it by name, or use the height of the "in between" layer as a the marker (if (l > object_height)) or use a layer-prop to determine how it's used. it's up to you, and the layers are drawn independently in all cases.

Also, I'm using custom-properties in all these examples, but you could also use the type or name field (from the object, not props) to set the sprite, or even assign a tile to it, and work out how to draw that tile in kaboom (hint: it should be in keys, keyed numerically) it's not something I want to manage in this lib. You do that however you want.

konsumer commented 3 years ago

I still think it's outside the job of this plugin, but I whipped up a quick ysort demo. You will probly want to tune movement and make the collision stuff more efficient, and it's just my take, you really should consider something that works well for your particular game, but I think it has the basic idea:

Use arrows to move one sprite behind and in front of things.

2021-10-13 08 28 43

I'm going to mark this closed, as it's not something I want to integrate into the tiled-loading plugin, but I think this illustrates how to do it your own way.

blurymind commented 3 years ago

Hey thanks for updating the demo. I will have a look in the morning. Yeah I made the tiled plugin for gdevelop, but am kind of hopeful other developers will join in progressing it with time.

The kaboomjs extension here really interests me for the sole reason of combining it with my tilemap editor at some point. I started writing a tiled importer and exporter for it and needed something to motivate myself this is going in the right direction.

Basically I want a kaboomjs dev environment in the browser with a tilemap editor and this extension here is the missing link between the two. It is getting closer

On Wed, 13 Oct 2021, 18:31 David Konsumer, @.***> wrote:

Closed #12 https://github.com/notnullgames/tiled-kaboom/issues/12.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/notnullgames/tiled-kaboom/issues/12#event-5458101712, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABRRWVISTVM7EFXY6LPHNF3UGWQ5TANCNFSM5FXRVDTA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

blurymind commented 3 years ago

The demo doesn't really have the player interact with things in the tilemap though - for example the waterfall. My thinking is for stuff like trees, bushes, waterfalls.

Rpg maker mv didn't seem to try to address this while using pixi tilemap, so I was a bit curious how another developer would do it

On Wed, 13 Oct 2021, 23:09 Todor Imreorov, @.***> wrote:

Hey thanks for updating the demo. I will have a look in the morning. Yeah I made the tiled plugin for gdevelop, but am kind of hopeful other developers will join in progressing it with time.

The kaboomjs extension here really interests me for the sole reason of combining it with my tilemap editor at some point. I started writing a tiled importer and exporter for it and needed something to motivate myself this is going in the right direction.

Basically I want a kaboomjs dev environment in the browser with a tilemap editor and this extension here is the missing link between the two. It is getting closer

On Wed, 13 Oct 2021, 18:31 David Konsumer, @.***> wrote:

Closed #12 https://github.com/notnullgames/tiled-kaboom/issues/12.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/notnullgames/tiled-kaboom/issues/12#event-5458101712, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABRRWVISTVM7EFXY6LPHNF3UGWQ5TANCNFSM5FXRVDTA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

konsumer commented 3 years ago

The kaboomjs extension here really interests me for the sole reason of combining it with my tilemap editor at some point.

I have no interest in implementing this, but you are free to use my code in your editor. Give credit, and use whatever you like.

Basically I want a kaboomjs dev environment in the browser with a tilemap editor and this extension here is the missing link between the two.

Yeh, Tiled already serves this purpose for me. It's pretty good. I have a long history with Tiled. Before Kaboom even existed, I helped build the current plugin system it has. Before that I used it for years. I am a big fan. It's really well-made software. As a related sidenote, have you seen Textyle? it's works on the web, and is open-source & is really nice to use. Maybe you could go add features to that (looks like they have a pretty nice list of cool TODOs.)

it is getting closer

Not really sure what more you expect the guy who made a plugin that loads Tiled maps in kaboom, to do. It fulfills the original need I had, and I happily accept PRs for features I agree would be cool (like animation and shared tilesets.) There are a few issues to track features I care about, feel free to tackle any of them. I will merge any code that looks ok, and try to help you through it, if it's not ok.

The demo doesn't really have the player interact with things in the tilemap though - for example the waterfall.

It's interacting with the other "enemy" player-sprites (so I only need a single sprite image and don't need to go lookup how to load a sub-region of an image.) I think you need to use your imagination a bit, and extrapolate what you want from the demos, and try things out on your own, like write some actual code. It's your usecase, not mine. All the pieces are there. If it were me, actually needing this in my game, I would write a utility function that takes an object-layer and renders it how I want. I would probly also add stuff to sprites based on object-properties (as I do in the sample above.) For over/under water, you should take the water that is not the part hitting ground and put them on a "definitely over player" layer, then put the z-fighting part (the tiles that touch the ground) on a layer where you do Y-sort, like I do in my demo above.

Rpg maker mv didn't seem to try to address this while using pixi tilemap, so I was a bit curious how another developer would do it

I don't follow. My above code illustrates how to do that.

There is a great kaboom video series where an awesome dev makes a zelda clone. She uses all the same ideas here, but much more complete code, and polished up things like movement and goes over these concepts in depth. She is using manual text maps (instead of converting Tiled maps into text, like this plugin does) but otherwise all the same stuff. They are great videos, and working through them may resolve any of your "a tiled map loader plugin maybe should do X", most of which I will probly disagree with (kaboom itself can do a lot of that stuff, and I am not trying to implement every possible usecase, just load Tiled maps, which this plugin does.)

blurymind commented 3 years ago

Yeh, Tiled already serves this purpose for me. It's pretty good. I have a long history with Tiled. Before Kaboom even existed, I helped build the current plugin system it has. Before that I used it for years. I am a big fan. It's really well-made software. As a related sidenote, have you seen Textyle? it's works on the web, and is open-source & is really nice to use. Maybe you could go add features to that (looks like they have a pretty nice list of cool TODOs.)

I have yeah. Textyle is not purely javascript though and can not be used as an npm module. That kindof put me off it

I dont care about interaction as much as correct rendering of the sprite when it is behind a tile. That is sort of the thing I wonder this extension can solve without being changed. I personally dont think it can when you cant tell it to only load a specific layer. You will be forced to have stuff like trees/waterfalls be rendered in some other way in order to let the player/enemies be behind them

image

A solution is to as you say have two tilemaps - above and bellow player. The bellow one only loads the bellow layers, the above one - only the above ones. If we cant tell it which layers to load, you have to create two tiled files for each map.

There is a great kaboom video series where an awesome dev makes a zelda clone...

yeah I know. I love her videos :) she got me into kaboomjs

konsumer commented 3 years ago

A solution is to as you say have two tilemaps - above and bellow player.

Well, that is one solution, that I personally would use for a specific "zelda type game", but that is my point, I think it's very game/developer specific. I am working on a side-scroller like super-mario that would have very different solutions to similar issues. I am finding all kinds of things specific to that, for example, it has really long levels that seem to render wrong, which could be a problem with kaboom or my plugin. Update: resolved that. I had height/width inverted. surprised I didn't notice before.

With your particular example, I think there are several different ways to solve the "I want the waterfall to appear over the player, and the ground to be over/under correctly". I feel like the solution I outlined would fix it in that case, in a pretty simple way.

I want to keep this library actually focused on what it's for, and not get off into a lot of edge-cases. I think kaboom itself can do a lot to configure how it all fits together, and just using the map-object to do "special things" that don't fit neatly into "turn a tiled map into a kaboom level". I think the other stuff is a matter of documentation (make actual examples that use the different techniques) into things that should be built into the library. Get to know how to do what you are asking for form the tiled-importer, and you can just do that pretty easily with what it outputs, yourself.

yeah I know. I love her videos :) she got me into kaboomjs

So good. Like informative, explained well, interesting projects. All together, pretty awesome.

Sidenote: not sure why you changed the title. As I said, you can "load specific layers", that is in fact how this plugin works, and I outlined several ways to do this, above. The example code does it in a loop, because it just shows how easy it is to "render all the layers" but it's a trivial matter of basic javascirpt to load them some other way, and it just uses regular kaboom stuff.

konsumer commented 3 years ago

Maybe we need a more concrete example. Why don't you make a demo that has the problems you think my library should solve for you, and I can show you specifically how to solve them, as needed, in an actual demo that will benefit other people?

Keep in mind, I disagree that a general ysorting solution for every game/style is something that is needed in every game that uses tiles, and different style games will have different solutions. I feel similarly about a lot of things, so it will be lots of "use the data in mabObj and basic kaboom stuff to do that"

konsumer commented 3 years ago

Textyle is not purely javascript though and can not be used as an npm module. That kindof put me off it

Not sure what you mean. It is all javascirpt. It's not published on npm, but I think it is meant to be a complete web-based app, you can deploy yourself (it's not a library.) See "Integrating a Textyle map to your project" in their README to see how to use it with other things. I think the idea is it's not ready-made for all possible scenarios (nothing is) but you can use it as a base to integrate with something else.

konsumer commented 3 years ago

A quick hint for your game-specific (not part of my plugin) issue, and this is essentially what I said before, but maybe I wasn't clear:

add a boolean "over" prop to levels you want to appear over player Screenshot from 2021-10-14 16-29-24

Add any layers that z-fight similar to how I did with 3 player sprites above

write code that does this:

// return a nice object for an array of Tiled properties
function getProperties(object) {
  return object?.properties?.reduce((a, v) => ({ ...a, [v.name]: v.value }), {}) || {}
}

const info = mapObj.layers.filter(layer => layer.type === 'tilelayer')
const allProps = []

// layers that are not over
for (const l in levels) {
  allProps.push(getProperties(info[l]))
  if (!allProps[l].over){
    addLevel(levels[l], { width: 32, height: 32, ...key })
  }
}

// TODO: add your sprite for player and things that z-fight, however you want, like above examples

// layers that are over
for (const l in levels) {
  if (allProps[l].over){
    addLevel(levels[l], { width: 32, height: 32, ...key })
  }
}

Screenshot from 2021-10-14 18-41-58

Again, this is just 1 way to do it. For example, instead of "over" you could look at the actual layer-orders and render them in order (dealing with object layers, sandwiched between tile layers.) You could bin the layers however you want, like even just by name (in code check for "Over" or in the example, "Waterfalls", and don't render that under player.)

The idea is to just use regular JavaScript stuff to manage it however you want. The code is the config.