mfessenden / sktiled Goto Github PK
View Code? Open in Web Editor NEWSwift framework for working with Tiled assets in SpriteKit
License: Other
Swift framework for working with Tiled assets in SpriteKit
License: Other
Hi, I'm trying to change a image of a tile, but it does not change.
I don't know if I'm doing the right way.
Can someone please help me?
These two new features of Tiled will not work inside Xcode.
After the map is loaded, some elements on the map need to perform interaction after the user clicks, such as jumps, bubbles, etc.
Is this feature currently supported?
On Xcode 12 - M1Mac i have trouble to set this Framework up as described.
with Carthage I get this error:
Building universal frameworks with common architectures is not possible. The device and simulator slices for "SKTiled" both build for: arm64
Rebuild with --use-xcframeworks to create an xcframework bundle instead.
cocoapods doesn't work either.
on Xcode 13 beta5 I tried to add the Framework directly via "File->Add Package" and pasted the GitHub link - still no luck, it was unable to resolve dependencies
im new to Xcode/iOS
please update install instructions for this framework
thanks!
Maybe this is not properly a bug or issue, but an improve.
Suppose we have a layer in our map that represent a wall, composed by little rectangles with a texture, and we have this code to get the layer:
self.wallsTilesLayer = self.tilemap.getLayer(named: "walls") as! SKTileLayer
Now to get the physicsBody we can do:
self.wallsTilesLayer.setPhysicsBody()
that call this method of your framework:
open func setupPhysics(isDynamic: Bool=false){
physicsBody = SKPhysicsBody(edgeLoopFrom: self.boundingRect)
physicsBody?.isDynamic = isDynamic
}
So, if you have a layer composed by many rectangle with textures around your map, this physicsBody cover only the bounding rectangle of your map.
That's not enough.
Now we suppose that a normal user set all tiles of his wall with the property string "wall", we can obtain the array of tiles that composed all the wall layer with :
self.wallsTiles = wallsTilesLayer.getTilesWithProperty("wall", "" as AnyObject)
One of the immediate error we can do is to create a physicsBody for each tile of the array, something like:
for wallTile in wallsTiles {
wallTile.setupPhysics(isDynamic:false)
}
This work , but it generate a giant amount of physics bodies to check and this drop your FPS.
A good thing to avoid this problem could be make an array of SKPhysicsBodies:
var wallBodies = [SKPhysicsBody]()
for wallTile in wallsTiles {
let wallBody = SKPhysicsBody.init(edgeLoopFrom: wallTile.frame)
wallBody.isDynamic = false
wallBodies.append(wallBody)
}
let wall = SKPhysicsBody.init(bodies: wallBodies)
self.wallsTilesLayer.physicsBody = wall
I don't know if your function was an error but I just want to report my idea to improve the physics.
Hi,
there seems to be an issue with these two methods in the SKTileMap class:
/**
Returns a tile at the given coordinate from a layer.
- parameter coord: `CGPoint` tile coordinate.
- parameter name: `String?` layer name.
- returns: `SKTile?` tile, or nil.
*/
open func tileAt(coord: CGPoint, inLayer: String?) -> SKTiled.SKTile?
open func tileAt(_ x: Int, _ y: Int, inLayer name: String?) -> SKTiled.SKTile?
Output in debugger:
(lldb) po tilemap.tileAt(0, 0, inLayer: "walls")
nil
(lldb) po tilemap.tileAt(coord: CGPoint(x: 0, y: 0), inLayer: "walls")
nil
But this works:
(lldb) po (tilemap.getLayer(named: "walls") as! SKTileLayer).tileAt(0, 0)
▿ Optional
▿ some : Tile ID: 481 @ 16x16, Layer: "walls"
Is it broken or is that expected behaviour?
UPDATE, this seems to work as well:
(lldb) po tilemap.tilesAt(0, 0)
▿ 2 elements
▿ 0 : Tile ID: 1153 @ 16x16, Layer: "ground"
▿ 1 : Tile ID: 481 @ 16x16, Layer: "walls"
First of all, great work on this project! I think generally it's easy to use. I forked a branch for tvOS and perhaps I will in the future submit a patch, if I can adapt the Demo project properly for tvOS.
Now for my question ...
In my current level setup I have to following:
Now it is difficult for me to read this property directly using the SKTiled framework. It seems I have to resort to a bit of "hackery" to read the value for "breed". Currently I do this as follows:
if let tile = object.value(forKeyPath: "tile") as? SKTile {
if let breed = tile.tileData.stringForKey("breed") {
print("breed: \(breed)")
}
}
The "hackery" in this situation is the fact that I use value(ForKeyPath:)
to access to tile
property, in order for me read the value for the breed
property.
I don't know if it's a good idea to make the tile
property publicly accessible, but I would like to have some cleaner way to access these kind of properties.
Perhaps I am doing something wrong or perhaps this is an area where the framework could improve.
I've a map maked with "Tiled Map Editor" version 1.4.2 and all is perfect using this editor.
When I try to load all map and assets inside my game, strange things happened during the loading of tiles taken by tilesets based on tilesets image (multiple tiles in one big image).
It seems the ID taken is the previous in the tile sequence, so instead of showing TILE ID 4, SKTiled show ID 3.
I was searching for the exact responsible method and I've found it:
public func getLocalID(forGlobalID gid: Int) -> Int {
// firstGID is greater than 0 only when added to a tilemap
let id = (firstGID > 0) ? (gid - firstGID) : gid
// if the id is less than zero, return the gid
return (id < 0) ? gid : id
}
if I change this line the tilesets based on tilesets showed correctly all tiles, but the rest of the map is total black
let id = (firstGID > 0) ? (gid - firstGID) + 1 : gid
Any idea about it? Could I distinguish tilesets based on tilesets from traditional tilesets to apply a condition and solve it?
Thank you in advance for all your support.
In testing intergration, I'm testing touch events, highlighting a tile when it's touched.
In my touchBegan
function, I have the following...
let layer = Game.sharedInstance.tileMap?.getLayer(atIndex: 0) as! SKTileLayer
let coord = layer.coordinateAtTouchLocation(touch)
let tile = layer.tileAt(coord: coord )!
tile.highlightColor = SKColor.blue
tile.highlightDuration = 2
tile.showBounds = true
When I touch a tile, I expect it to highlight blue, but it highlights using the default colour, lime.
I tried to set the highlight colour for the whole Tilemap...
Game.sharedInstance.tileMap?.highlightColor = SKColor.orange
Still, does not change the colour.
I in stead change the frameColor...
tile.frameColor = SKColor.blue
And this has the desired effect.
highlightColor
doesn't seem to be the colour used for highligting a tile. Am I implementing the "highlight a tile" functionality wrong? This seemed to be how it was done in the documentation and the example project.
Thanks in advance.
Hi, I have another question.
Can I limit the pan in my scene?
I can pan infinitly and I want to use only the region of my tiles and a little of the border of the tiles.
I tried this way:
if position.x < 68 { position.x = 68 }
if position.x > 108 { position.x = 108 }
if position.y < 30 { position.y = 30 }
if position.y > 50 { position.y = 50 }
But when I zoom the camera, this positions change and It does not work properly anymore.
My tile map is little, about 7x4, and there is some pictures at its side, so it is pratically my workspace.
Is there a way to limit the pan to this little area, and be able to zoom limiting this same area?
Thanks!
To get this to build in iOS 11, I had to remove the zlib module included in the repository and add OTHER_LDFLAGS = "-lz"; to the project.
Hi, first of all thank you for the amazing framework! It's really hard to find stuff on tile maps in swift, so this framework really helps.
I'm trying to use layer.addTileAt
to change a tile at a coordinate, but I'm running into an issue. Calling that function removes the tile, but it doesn't replace the tile with a new one. For example, downloading your repo and adding this line of code on line 450 of SKTiled/Demo/SKTiledDemoScene.swift after updatePropertiesInfo()
:
let newTile = (tilemap.getLayers(named: "Ground")[0] as? SKTileLayer)?.addTileAt(coord: coord, gid: 41)
Should change the tile to a new tile with gid 41 (I think this corresponds to a wall tile?) but it only removes and doesn't replace the tile. I tested this on the isometric (second) map. It seems to return the proper wall tile but it isn't visible, but I couldn't figure out how to fix this issue.
Any help would be greatly appreciated!
When presenting a new scene it appears not all memory is freed.
The Demo project shows this, when repeatedly pressing "next" cycling through the maps, memory usage goes up, and never down. On the iOS Simulator I see ± 1MB increased memory used each time, on macOS I see ±5MB of increased memory use each time. The memory graph never goes down.
When trying my own app, with a single TMX file (eg. the famous level1.tmx file from this example) I get 100 MB (!) of increased memory use on macOS and 2 MB on iOS Simulator every time a new SKTiledScene is presented with that map.
When trying with an empty TMX map of size 10x10 tiles with no content, I get 120 MB of increased memory use on macOS and 0.2 MB on iOS Simulator every time a new SKTiledScene is presented.
It appears to me that on macOS the problem is huge, on iOS it is doable
The SKTiledScene.deinit
gets called each time so the scene is cleaned up correctly (I think?)
When debugging with Xcodes memory graph it shows no problems or leaks. However, if I don't load a map with SKTiledScene.setup(....)
the issue does not occur.
When I override deinit
in all classes and print a debug text, I can see that only SKTilemapParser
gets deinit
ed immediately after loading the map. All other classes are never deinit
ed.
When I started with your framework I noticed that everything worked fine except that some of my nodes disappeared only when SKTiled was imported for the first time.
After hours of investigation, I noticed that you added a convenience init to SKColor and since I was using the classical range of alpha value, your init was overriding the UIColor one and making my colored sprites with an alpha value near 0.
I've built the framework and successfully imported into an objective-c project.
#import "SKTiled/SKTiled-Swift.h"
All the SKTiled classes are now recognized but not their methods. Am I correct in assuming the SKTiled
framework can be used inside objective-c projects? If so, how?
I'm pushing my SKView / SKTiledScene on a navigation controller from a vanilla UIKit menu view.
When I hit 'Back' on the navigation controller, I encounter a crash, but only on an iPhone 5:
2017-04-29 20:36:37.847 MyGame[32197:8936930] *** -[SKTiledScene release]: message sent to deallocated instance 0x7bf07ba0
It appears to be caused by the removeAllChildren()
in the deinit
of SKTiledScene
.
Commenting it out address my problem, although at this time I'm not exactly sure why. It also doesn't appear to have a negative impact on my memory usage.
Hello everyone, I just cloned the repo and all is working properly, even adding my files into /User
folder and works properly on demo-project.
But not on my own project, there is not loading as simple documentation says:
if let tilemap = SKTilemap.load(tmxFile: "dungeon-16x16.tmx") {
addChild(tilemap)
}
It's actually adding an node, but is empty, also is failing with the following message:
[SKTilemapParser]: INFO: tmx parser: reading tile map: "dungeon-16x16.tmx"
[SKTilemapParser]: FATAL: tileset file not found: "dungeon-16x16.tsx".
[SKTilemapParser]: ERROR: tmx parser: The operation couldn’t be completed. (NSXMLParserErrorDomain error 512.) at line: 10, column: 50
✽ Success! tilemap "dungeon-16x16" rendered in: 0.012s
(This files are from the sample, but I'm running same problem with any group of files)
Any idea? I have all files on my target, but in difference with the demo project, I cannot add the tsx files my my now in Target Membership
tab, any idea?
I think can be related to TSX files are recognized as TypeScript files, but I'm not sure.
Thanks!
While it is easy to get the tiles using tileAt(coord: tileCoord)
from the SKTilemap
or SKTileLayer
, there is no reverse method that gives me the coords for any given SKTile
.
I would like to be able to get the coords from the SKTile
itself.
(I could calculate them myself my using something like tilemap.coordinateForPoint(tile.position)
but that seems complicated and may not be accurate depending on the parent node of the tile.)
thanks
I'm testing out this library as a possible means to load in default maps and manage maps for a biz sim game.
The MacOS demo application seemed to work OK with the sample tilemaps.
I tried loading in my own tilemap (50x50 at 64px), sometimes it loads fine, but others it only loads to y31 graphically.
I can still see the mouse over triggers change for the lower part of the image, even though I can't see it.
When i click "show grid", this then changes so only x18 and beyond are shown, but all of y is shown.
Seems pretty weird to me. It's an intermittent issue, so it seems. (I'm sorry.)
Here are the attached tilemap and pallet file.
tileset.zip
(I had to upload them as a zip because of github restrictions.)
I don't want to spend time intergrating this tilemap solution into my current setup if there are problems with maps of that size.
I'm running version 1.21.
Running on MBP 13" 2017 on MacOS 10.13.6
Whenever I try to leave my class that inherits SKTiledScene using view.presentScene() and then display the tile map again, memory isn't released when it should be. A simple example is using your demo iOS project: switching between the various tilemaps increases the memory even when I go back to the first one, which will eventually result in a crash. I'm suspecting that there's a strong reference cycle in SKTiledScene that's stopping the tilemap from being deallocated, but I can't find it myself. Any help would be greatly appreciated!
The function in subject crash to the line:
let imageDataProvider = CGDataProvider(url: urlPath as CFURL)!
This because the final path inside the bundle could be not the same as source input.
I've solved changing this part of code:
public func addTilesetTile(_ tileID: Int, source: String) -> SKTilesetData? {
guard !(self.tileData.contains(where: { $0.hashValue == tileID.hashValue })) else {
log("tile data exists at id: \(tileID)", level: .error)
return nil
}
// bundled images shouldn't have file paths
//let imageName = source.componentsSeparatedByString("/").last!
isImageCollection = true
let inputURL = URL(fileURLWithPath: source)
// read image from file
let imageDataProvider = CGDataProvider(url: inputURL as CFURL)!
with:
public func addTilesetTile(_ tileID: Int, source: String) -> SKTilesetData? {
guard !(self.tileData.contains(where: { $0.hashValue == tileID.hashValue })) else {
log("tile data exists at id: \(tileID)", level: .error)
return nil
}
// bundled images shouldn't have file paths
//let imageName = source.componentsSeparatedByString("/").last!
isImageCollection = true
let inputURL = URL(fileURLWithPath: source)
let filename = inputURL.deletingPathExtension().lastPathComponent
let fileExtension = inputURL.pathExtension
guard let urlPath = Bundle.main.url(forResource: filename, withExtension: fileExtension) else { return nil }
// read image from file
let imageDataProvider = CGDataProvider(url: urlPath as CFURL)!
I'm creating a game for apple watch and I would love to use your framework. TileKit is horrible to design levels with.
Would this be possible you think?
Sorry to bump an older project!
The tvOS target is missing from the SKTiled podspec downloaded from the Cocoapods master repo.
{
"name": "SKTiled",
"version": "1.20",
"summary": "SKTiled is a framework for using Tiled content with Apple's SpriteKit.",
"description": "SKTiled is a framework for using Tiled content with Apple's SpriteKit, allowing the creation of game assets from .tmx files.",
"authors": {
"Michael Fessenden": "[email protected]"
},
"homepage": "https://github.com/mfessenden/SKTiled",
"license": {
"type": "MIT",
"file": "LICENSE.md"
},
"platforms": {
"ios": "11.0",
"osx": "10.13",
},
"source": {
"git": "https://github.com/mfessenden/SKTiled.git",
"tag": "1.20"
},
"source_files": "Sources/*.swift",
"requires_arc": true
}
The tvOS target should be added, as is in this repo.
Why Requirements iOS10+?
It seem work fine in iOS9+ .
Hi there!
First of thanks for this amazing project, it's very useful and nicely built.
Having the ability to import tmx files straight into SpriteKit is incredibly valuable :)
I have some question though. I am working on a new project, and setting up the toolset. One of the main challenges I see is that I want to be able to render quite large maps (eg 300300tiles) without loading screens etc. The tiles are 3232, but that is not really important now. I preferably design the maps in Tiled, though that is not a must.
Now I tried two API's to draw large tile maps having 90K tiles. I tried SKTiled, and I really liked the easiness of putting a tmx map in there and it works OOTB. But I found that the performance is not optimal, which I sort of expected with SpriteKit having to take care of 90K nodes, even though not all are rendered ofc. Especially tile cracking is an issue, which I couldn't resolve with the proposed actions here.
Enabling shouldEnableEffects
also didn't really help, as the map is larger than the max framebuffer texture size is exceeded in my case, making parts of the map being cropped out.
I gave SKTileMapNode a shot as well. This has an obvious downside, being that built-in Xcode map editor is quite a mess. But drawing the map does result in only 1 node being drawn, instead of 90K. Moreover, the tile cracking isn't an issue as well.
So I conclude out of this that the usability of SKTiled greatly exceeds that of the SKTileMapNode and related API's and map building capabilities. But, the performance optimizations of SKTileMapNode are probably not to be matched.
Hence, I wonder if it might be possible to use tmx files, post process them in some way, and as a result have a SKTileMapNode
being produced, either fully in code or as .sks
file. Possible it probably is, whether its worth the effort that yet remains to be uncovered. But before I loose myself in this problem, what are your thoughts on this, and did you ever consider the same for example?
Sorry to create an issue for this, I couldn't find another way to reach out to you.
Cheers,
Sander
Hey,
When i try to install 1.12 version i get this error :
[!] Unable to satisfy the following requirements:
- `SKTiled (~> 1.12)` required by `Podfile`
None of your spec sources contain a spec satisfying the dependency: `SKTiled (~> 1.12)`.
You have either:
* out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
* mistyped the name or version.
* not added the source repo that hosts the Podspec to your Podfile.
Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
I searched at cocoapods.org and the version number was 1.07
When i change my podfile to SKTiled (~> 1.07) it works.
Thanks for maintaining this awesome project!
As a new game dev, I'm looking for some information:
• player / enemies: do I add them as children on the SKScene, on the world node, on the tilemap, or on a layer?
• collision detection: as collision objects are not supported in SKTiled, should I add SpriteKit collision masks to all tiles and didBegin(_ contact:), or for example check for the presence of tiles near the player position?
Thanks!
let coord = playerLayer.pointForCoordinate(13,1)
let point = playerLayer.coordinateForPoint(coord)
point != 13,1... (result is 13,2).
Why? => return CGPoint(x: floor(pixelX / tileWidth), y: floor(pixelY / tileHeight))
if the position is from 13,1 for example (216.0, -24.0) then the outcome from pixelY / tileHeight is 2.
Edit: Map is Orthogonal
Edit2: Fixed it with +tileHeight or -tileHeight the pixelY
I recently updated from 1.12 to 1.16 and am seeing some significant performance issues. From around 5% CPU and 60 FPS (v1.12) to 100% CPU and 5 FPS (v1.16).
This performance drop appears to be because of the work in update
on SKTile
. I don't want to set tilemap.isPaused = true
because I have other animations I want to run. But at rest, none of my tile map animates.
I heavily rely on the scaling objects in ObjectsLayer inside Tiled.
now all object-scaling seems to be ignored by SKTilemap .. that's really unfortunate - all my map layout is broken that way
is there a fix / workaround for that?
I have a flat-topped tilemap setup in Tiled as follows:
<map version="1.0" orientation="hexagonal" renderorder="right-down" width="16" height="16" tilewidth="75" tileheight="65" hexsidelength="40" staggeraxis="x" staggerindex="odd" nextobjectid="9">
I'm having an issue with 'coordinateForPoint' not returning the correct coordinates for me.
I narrowed it down to this method in 'screenToTileCoords':
if (tilemap.staggerX == true) {
s = tilemap.sideLengthX
r = (tileWidth - tilemap.sideLengthX) / 2
h = tileHeight / 2
pixelX -= r
sectionX = pixelX / (r + s)
sectionY = pixelY / (h * 2)
// y-offset
if tilemap.doStaggerX(Int(sectionX)){
sectionY -= 0.5
}
Specifically: pixelX -= r
. This causes pixels in the left-side tip of a flat-topped hex tile to be calculated to the previous X column. Removing this line causes pixels in the right-side tip of a flat-topped hex tile to be calculated to the next X column.
Barring any significantly more complicated calculations to figure out the column of an angled side, I split the difference with pixelX -= (r / 2)
and it seems to be working 'good enough' for me. I'd appreciate your thoughts!
On the documentation website, the "install to dash" button has the URL...
file:///Users/michael/git/SKTiled/docsets/SKTiled.xml
.
Obviously this is wrong.
It should be https://mfessenden.github.io/SKTiled/docsets/SKTiled.xml
or probably /SKTiled/docsets/SKTiled.xml
.
It looks like this is a generation setting, as it's included in every HTML file in the gh-pages branch, so I guess I can't submit a PR.
On line 840 inside SKTilemapParser I get:
Thread 1: signal SIGABRT
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Hi,
For iOS and macOS projets it's will be great to make your component Carthage compatible
Take a look at these articles:
On your README.md
add on top and add section for the installation with Carthage.
Hello Michael, seems that sometimes the actual framework (v.1.07) crash with the message on subject. The crash is stopped to appDelegate so there isn't a specific line of code, but during my analisys to the debug error output, I've discovered the array layers
is involved when the tileLayers are in paused mode. So I've change this code:
SKTiledMap.swift (original)
/// Pauses the node, and colors all of its children darker.
override open var isPaused: Bool {
didSet {
guard oldValue != isPaused else { return }
let newColor: SKColor = isPaused ? SKColor(white: 0, alpha: 0.25) : SKColor.clear
let newColorBlendFactor: CGFloat = isPaused ? 0.2 : 0.0
speed = isPaused ? 0 : 1.0
color = newColor
layers.forEach { layer in
layer.color = newColor
layer.colorBlendFactor = newColorBlendFactor
layer.isPaused = isPaused
//layer.speed = speed
}
}
}
with this code:
/// pauses the node, and colors all of its children darker.
override open var isPaused: Bool {
didSet {
guard oldValue != isPaused else { return }
let newColor: SKColor = isPaused ? SKColor(white: 0, alpha: 0.25) : SKColor.clear
let newColorBlendFactor: CGFloat = isPaused ? 0.2 : 0.0
speed = isPaused ? 0 : 1.0
color = newColor
let tempLayers:Set<TiledLayerObject> = layers
tempLayers.forEach { layer in
layer.color = newColor
layer.colorBlendFactor = newColorBlendFactor
layer.isPaused = isPaused
//layer.speed = speed
}
layers = tempLayers
}
}
where I've found a workaround ,I've created a temporary array to avoid enumeration to the original..
I've found also this file:
SKTileLayer.swift
override open var isPaused: Bool {
didSet {
tiles.forEach { tile in
tile?.color = self.color
tile?.colorBlendFactor = self.colorBlendFactor
}
}
}
where I've maded:
override open var isPaused: Bool {
didSet {
let tempTiles:TilesArray = tiles
tempTiles.forEach { tile in
tile?.color = self.color
tile?.colorBlendFactor = self.colorBlendFactor
}
tiles = tempTiles
}
}
Hi, how would I go about animating a SKTileObject in code?
The animations exist within the object's tileset, but the object is not animated to begin with.
Do I manually need to create SKActions or do I change the tileData ID somehow?
How can I intercept the end of the map loading without completions or delegate if my code follow your home instructions? How can I use callbacks?
// Load TileMap
guard let tilemap = SKTilemap.load(fromFile: currentTMXfilename) else {
fatalError("Failed to load tilemap.")
}
after this line if I try to get a SKLayer, is always nil (I suppose because the map don't finish to load all components..) ..
Thank you in advance.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.