英文:
Tiled collision editor, object layer in use in Phaser
问题
我已经在Tiled中以这种方式添加了树碰撞。如何在Phaser中使用这个碰撞与玩家发生碰撞?
英文:
I have added tree collision this way in Tiled.
How can I use this collision to collide with the player in Phaser?
答案1
得分: 1
这是一个示例代码,用于处理Tiled地图中的碰撞物体。以下是其中的一些部分的翻译:
-
获取Tiled地图中指定名称的对象层 (链接到文档):
let objectLayer = map.getObjectLayer('Trees');
-
遍历该层中的所有对象 (链接到文档):
for (let obj of objectLayer.objects) {
// ...
}
-
针对每个来自该层的对象:
根据对象类型(点、矩形、椭圆等)创建碰撞用的物理体(在此示例中使用椭圆):let ellipse = this.add.ellipse(obj.x, obj.y, obj.width, obj.height);
// 你可能需要设置“origin”
this.physics.add.existing(ellipse, true);
ellipse.body.setCircle(obj.width / 2);
-
设置与玩家、AI等的碰撞:
this.physics.add.collider(player, ellipse);
请注意,这段代码中的关键部分用于处理Tiled地图中的对象和碰撞,以及如何为它们创建适当的物理体。希望这有所帮助。
英文:
Well there are many way's to do this, this is one way:
<!-- language-all: lang-js -->
-
get object layer, with the name from Tiled (link to the documentation):
// let map = this.make.tilemap( {...} );
let objectLayer = map.getObjectLayer( 'Trees' );
-
iterate over all objects from that layer (link to the documentation):
for( let obj in objectLayer.objects ){
// ...
}
-
For each
object
from thelayer
:
Depending on your object type (point, rectangle, ellipse, ...) you create the physics-body for the collision (for this example I will use a ellipse):let ellipse = this.add.ellipse( obj.x, obj.y, obj.width, obj.height );
// you might need to set the "origin"
this.physics.add.existing( ellipse, true );
ellipse.body.setCircle(obj.width / 2);
> Info/Tipp: if you are using arcade physics the "hitbox" will be a rectangle, doesn't matter which
gameObject
you use. If you want round physics body with arcade you could use thesetCircle
method on thebody
(link to documentation). For complex shapes I would recommend using the matter.js engine. -
Setup collision with: player, ai, ...
this.physics.add.collider( player, ellipse );
Updated running demo:
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
document.body.style = 'margin:0;';
let json_map = {"compressionlevel":-1,"height":5,"infinite":false,"layers":[{"compression":"","data":"AQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAA==","encoding":"base64","height":5,"id":1,"name":"TileLayer1","opacity":1,"type":"tilelayer","visible":true,"width":8,"x":0,"y":0},{"draworder":"topdown","id":2,"name":"ObjectLayer1","objects":[{"class":"","ellipse":true,"height":10,"id":1,"name":"","rotation":0,"visible":true,"width":10,"x":8,"y":8},{"class":"","height":5,"id":2,"name":"","rotation":0,"visible":true,"width":15,"x":19.2,"y":25.6},{"class":"","height":0,"id":3,"name":"","point":true,"rotation":0,"visible":true,"width":0,"x":48,"y":4.8}],"opacity":1,"type":"objectgroup","visible":true,"x":0,"y":0}],"nextlayerid":3,"nextobjectid":4,"orientation":"orthogonal","renderorder":"right-down","tiledversion":"1.9.2","tileheight":8,"tilesets":[{"columns":1,"firstgid":1,"image":"tiles.png","imageheight":8,"imagewidth":8,"margin":0,"name":"tiles","spacing":0,"tilecount":1,"tileheight":8,"tilewidth":8}],"tilewidth":8,"type":"map","version":"1.9","width":8};
let config = {
type: Phaser.AUTO,
width: 8 * 8,
height: 5 * 8,
zoom: 4,
physics: {
default: 'arcade',
arcade: { debug: true }
},
scene: { preload, create },
};
function preload () {
this.load.tilemapTiledJSON('map', json_map);
}
function create () {
let graphics = this.make.graphics();
graphics.fillStyle(0x933AFF);
graphics.fillRect(0, 0, 10, 10);
graphics.generateTexture('tiles', 10, 10);
let player = this.add.rectangle(50, 10, 5, 5, 0xffffff);
this.physics.add.existing(player);
player.setDepth(100);
player.body.setVelocityX(-10);
let map = this.make.tilemap({ key: 'map', tileWidth: 8, tileHeight: 8 });
let tiles = map.addTilesetImage('tiles', 'tiles');
let layer = map.createLayer(0, tiles, 0, 0);
let objectLayer = map.getObjectLayer( 'ObjectLayer1' );
for( let obj of objectLayer.objects ){
// since you are not displaying the object the shape doesn't matter, only the collision body
let gameObject = this.add.rectangle( obj.x, obj.y, obj.width, obj.height )
.setOrigin(0);
this.physics.add.existing( gameObject, true );
if(obj.ellipse){
// For the ellipse version you would need to change the body
gameObject.body.setCircle( obj.width / 2 );
} else if(obj.point){
// For the point we need no set an width and height
gameObject.body.setSize( 4, 4 );
}
this.physics.add.collider( player, gameObject );
}
}
new Phaser.Game(config);
<!-- language: lang-html -->
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>
<!-- end snippet -->
> Btw.: In my Tiled version even, when I create the circle-object the width
and height
, I had to set does properties manualy. So check them if they are set.
>
>
答案2
得分: 0
最终,我找到了解决方案,这对我有效。
addCollisionFromTiled(layerName: string, group: number) {
const graphics = this.scene.add.graphics().lineStyle(2, 0x00ff00, 1)
const objectLayer = this.map.getObjectLayer(layerName)
objectLayer.objects.forEach((object: Phaser.Types.Tilemaps.TiledObject) => {
if (object.rectangle) {
const rect2 = this.scene.add.rectangle(0, 0, object.width, object.height)
const polygon = new Phaser.Geom.Polygon(rect2.pathData)
const body2 = this.scene.matter.add.fromVertices(
object.x! + object.width! / 2,
object.y! + object.height! / 2,
polygon.points.slice(0, -1)
)
const collision = this.scene.matter.add.gameObject(
rect2,
body2
) as Phaser.Physics.Matter.Sprite
collision.setStatic(true)
collision.setCollisionGroup(group)
graphics.strokeRect(object.x!, object.y!, object.width!, object.height!)
} else if (object.ellipse) {
const elps2 = this.scene add ellipse(0, 0, object.width, object.height)
const polygon = new Phaser.Geom.Polygon(elps2.pathData)
const body2 = this.scene.matter add fromVertices(
object.x! + object.width! / 2,
object.y! + object.height! / 2,
polygon.points.slice(0, -1)
)
const collision = this.scene.matter add gameObject(
elps2,
body2
) as Phaser.Physics.Matter.Sprite
collision.setStatic(true)
collision.setCollisionGroup(group)
graphics.strokeEllipse(
object.x! + object.width! / 2,
object.y! + object.height! / 2,
object.width!,
object.height!
)
} else if (object.polygon || object.polyline) {
const objPol = object.polygon ? object.polygon : object.polyline
const polygon = new Phaser.Geom.Polygon(objPol)
const points: { x: number; y: number }[] = []
for (let point of polygon.points) {
points.push({
x: object.x! + point.x,
y: object.y! + point.y,
})
}
const sliceCentre = this.scene.matter.vertices.centre(points)
const body2 = this.scene.matter.add.fromVertices(sliceCentre.x, sliceCentre.y, points)
const poly2 = this.scene.add.polygon(sliceCentre.x, sliceCentre.y, points)
const collision = this.scene.matter.add.gameObject(
poly2,
body2
) as Phaser.Physics.Matter.Sprite
collision.setStatic(true)
collision.setCollisionGroup(group)
graphics.strokePoints(points)
}
})
}
英文:
Finally, I got a solution, and this is working for me.
addCollisionFromTiled(layerName: string, group: number) {
const graphics = this.scene.add.graphics().lineStyle(2, 0x00ff00, 1)
const objectLayer = this.map.getObjectLayer(layerName)
objectLayer.objects.forEach((object: Phaser.Types.Tilemaps.TiledObject) => {
if (object.rectangle) {
const rect2 = this.scene.add.rectangle(0, 0, object.width, object.height)
const polygon = new Phaser.Geom.Polygon(rect2.pathData)
const body2 = this.scene.matter.add.fromVertices(
object.x! + object.width! / 2,
object.y! + object.height! / 2,
polygon.points.slice(0, -1)
)
const collision = this.scene.matter.add.gameObject(
rect2,
body2
) as Phaser.Physics.Matter.Sprite
collision.setStatic(true)
collision.setCollisionGroup(group)
graphics.strokeRect(object.x!, object.y!, object.width!, object.height!)
} else if (object.ellipse) {
const elps2 = this.scene.add.ellipse(0, 0, object.width, object.height)
const polygon = new Phaser.Geom.Polygon(elps2.pathData)
const body2 = this.scene.matter.add.fromVertices(
object.x! + object.width! / 2,
object.y! + object.height! / 2,
polygon.points.slice(0, -1)
)
const collision = this.scene.matter.add.gameObject(
elps2,
body2
) as Phaser.Physics.Matter.Sprite
collision.setStatic(true)
collision.setCollisionGroup(group)
graphics.strokeEllipse(
object.x! + object.width! / 2,
object.y! + object.height! / 2,
object.width!,
object.height!
)
} else if (object.polygon || object.polyline) {
const objPol = object.polygon ? object.polygon : object.polyline
const polygon = new Phaser.Geom.Polygon(objPol)
const points: { x: number; y: number }[] = []
for (let point of polygon.points) {
points.push({
x: object.x! + point.x,
y: object.y! + point.y,
})
}
const sliceCentre = this.scene.matter.vertices.centre(points)
const body2 = this.scene.matter.add.fromVertices(sliceCentre.x, sliceCentre.y, points)
const poly2 = this.scene.add.polygon(sliceCentre.x, sliceCentre.y, points)
const collision = this.scene.matter.add.gameObject(
poly2,
body2
) as Phaser.Physics.Matter.Sprite
collision.setStatic(true)
collision.setCollisionGroup(group)
graphics.strokePoints(points)
}
})
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论