This is my code:
var spriteSheet = new createjs.SpriteSheet({
images: ["images/mario2.png"],
frames: {width:24, height:33, regX: 0, regY: 0},
animations: {
walk_right: [5, 9],
walk_up: [10, 14],
walk_down: [15, 19],
walk_left: [0, 4]
}
});
Player = new createjs.BitmapAnimation(spriteSheet);
Player.name = "Mario";
Player.gotoAndStop("walk_right");
Player.speed = 6;
Player.x = 30;
Player.y = 330;
//Player object toevoegen aan de stage
stage.addChild(Player);
var monsterspritesheet = new createjs.SpriteSheet({
images: ["images/MonsterA.png"], //image to use
frames: {width: 64, height: 54, regX: 0, regY: 0},
animations: {
walk: [0, 9, "walk", 4],
idle: [10, 20, "idle", 4]
}
});
Monster1 = new createjs.BitmapAnimation(monsterspritesheet);
Monster1.name = "Monster";
Monster1.gotoAndStop("walk");
Monster1.speed = 6;
Monster1.x = 180;
Monster1.y = 330;
stage.addChild(Monster1);
stage.update();
For hitTest I use the following code:
var testpos = Player.globalToLocal(Monster1.x ,Monster1.y);
if (Player.hitTest(testpos.x, testpos.y) === true)
{
console.log("HIT");
}
THE PROBLEM:
When my player is below my monster, i get the message "HIT" but I would like to get it to work whenever my player hits the monster and not when it is below it.
I have been playing with regX and regY of both Player & Monster but it doesn't seem to work. Anyone knows the solution?
I think your issue here is that you need a CollisionDetection but hitTest() will only check for one pixel, which is in most cases used for mouse-interaction-detection and is perfect for it. However using it for detecting collisions between two bitmaps might need a little more work than just testing for one pixel.
I would suggest you to use my CollisionDetection class for bitmaps and bitmapAnimations, it works with bounding boxes or pixel-perfect and you basically just need to change one line.
You can check it out on Github: Bitmap Collision Detection for EaselJS
Description is on the github.com Page. (just in case you'll use it: let me know if you run into any bugs)
Related
So I have been using the Chebyshev Distance example from the Phaser labs, and while this example was using one layer, I happen to be using two, and when i set transparency on them, the colors start leaking into each other, especially on light colors.
Is there any way to circumvent or get rid of this effect
If the problem is that you have two layers, one ontop of the other and you are making both transparent (or only the top one), and you don't want that color to pass through, the solution could be to hide the tiles on the bottom layer.
Just check in the map-tile-loop, if the tile, where you want to change the alpha, has a tile beneath it, and if so make that background tile transparent.
Here a small working demo:
(The main magic is in the updateMap function)
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
preload,
create
}
};
var player;
var bgLayer;
var point1 = {x: 250, y: 31};
var isLeaking = false;
new Phaser.Game(config);
function preload (){
this.load.image('tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'https://labs.phaser.io/assets/tilemaps/csv/catastrophi_level2.csv');
}
function create () {
this.add.text(50, 1, ' <- Background is visible, if no tiles are ontop')
.setOrigin(0)
.setDepth(100)
.setStyle({fontFamily: 'Arial'});
this.infoText = this.add.text(10, 20, 'Click to toggle leaking: on')
.setOrigin(0)
.setDepth(100)
.setStyle({fontFamily: 'Arial'});
// Just creating image for second layer tiles //
let graphics = this.make.graphics();
graphics.fillStyle(0xff0000);
graphics.fillRect(0, 0, 16, 16);
graphics.generateTexture('tiles2', 16, 16);
// Just creating image for second layer tiles //
let map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
let tileset = map.addTilesetImage('tiles');
let tileset2 = map.addTilesetImage('tiles2');
bgLayer = map.createBlankLayer('background', tileset2);
bgLayer.fill(0);
let fgLayer = map.createLayer(0, tileset, 0, 0);
// Just to show that the Background is still show if not Tile is covering
fgLayer.removeTileAt(0, 0);
fgLayer.removeTileAt(1, 0);
fgLayer.removeTileAt(2, 0);
player = this.add.rectangle(point1.x, point1.y, 5, 5, 0xffffff, .5)
.setOrigin(.5);
this.input.on('pointerdown', () => {
isLeaking = !isLeaking;
this.infoText.setText( `Click to toggle leaking: ${isLeaking?'off':'on'}` )
updateMap(map);
});
updateMap(map);
}
function updateMap (map) {
let originPoint1 = map.getTileAtWorldXY(point1.x, point1.y);
console.info(map.layers.sort((a,b) => b.depth - a.depth))
map.forEachTile(function (tile) {
var dist = Phaser.Math.Distance.Chebyshev(
originPoint1.x,
originPoint1.y,
tile.x,
tile.y
);
let bgTile = bgLayer.getTileAt(tile.x, tile.y, false)
let hideOnlyTheseTiles = [ 0, 1, 2, 3, 4]; // Indexes to hide
if( !isLeaking ){
if(hideOnlyTheseTiles.indexOf(bgTile.index) > -1){ // here yopu can select the
bgTile.setAlpha(0);
}
} else{
bgTile.setAlpha(1);
}
tile.setAlpha(1 - 0.09 * dist);
});
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I have a top down game and I need the player to be rendered below the bottom walls, and above the top walls, and my solution would be to set the depth of individual tiles in the tilemap by the tile ID. I can't use anything involving tiled, because my game will be procedurally generated. Maybe something similar to this:
this.wallLayer.forEachTile((tile)=>{
if(tile.id === 1){
tile.setDepth(1)
}
if(tile.id === 2){
tile.setDepth(3)
}
})
if there is a similar method I could use, it would be great if someone could point me in the right direction. Thanks!
I'm not sure if this is the best solution, but i would create two maps and place one over the other.
first map + layer is incharge for collision and everything the player should cover. Set a lower depth than the player.
second map + layer is incharge to be infront of the layer.
Using the function replaceByIndex, to remove indices that should not covered the player. (link to documentation) And setting a higher depth than the player
Here a short Demo showcasing this:
(use cursor-keys to move the player)
Red-Tiles should cover the player, blue tiles should be coverd by the player.
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536 /8,
height: 34,
zoom: 6,
physics: {
default: 'arcade',
arcade: {
gravity:{ y: 0 },
debug: false
}
},
scene: {
create,
update
},
banner: false
};
function create () {
let graphics = this.make.graphics();
graphics.fillStyle(0x00ff00);
graphics.fillRect(8, 0, 8, 8);
graphics.fillStyle(0xff0000);
graphics.fillRect(16, 0, 8, 8);
graphics.fillStyle(0x0000ff);
graphics.fillRect(24, 0, 8, 8);
graphics.generateTexture('tiles', 8*4, 8);
var level = [
[1,1,1,1,1],
[1,0,3,0,1],
[1,0,0,0,1],
[1,2,2,2,1],
]
// Map for the first level
var map = this.make.tilemap({ data: level, tileWidth: 8, tileHeight: 8 });
var tiles = map.addTilesetImage('tiles');
var layer = map.createLayer(0, tiles, 0, 0);
layer.setCollision(1);
var map2 = this.make.tilemap({ data: level, tileWidth: 8, tileHeight: 8 });
var layer2 = map2.createLayer(0, tiles, 0, 0);
layer2.setDepth(10);
//remove tile that should not overlap
map2.replaceByIndex(3, -1);
this.player = this.add.circle(16,16,4, 0xffffff)
.setDepth(2);
this.physics.add.existing(this.player);
// Just setup collision with the first layer
this.physics.add.collider(layer, this.player);
this.keys = this.input.keyboard.createCursorKeys();
}
function update(){
let speed = 20;
this.player.body.setVelocity(0)
if(this.keys.up.isDown){
this.player.body.setVelocityY(-speed)
}
if(this.keys.down.isDown){
this.player.body.setVelocityY(speed)
}
if(this.keys.left.isDown){
this.player.body.setVelocityX(-speed)
}
if(this.keys.right.isDown){
this.player.body.setVelocityX(speed)
}
}
new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
You might want to consider using some sort of map of tile IDs to their depths.
const tileDepthMap = {
1: 1,
2: 3,
};
or even as an array since your IDs are numerical:
const tileDepthMap = [0 /* or whatever depth for ID 0 */, 1, 3];
Then you'll be able to get the depth for an ID simply by indexing into it:
tileDepthMap[tile.id]
and you can also specify a default like this:
tileDepthMap[tile.id] ?? 0 // Default to depth of 0 if not found
I'm working on a game in Phaser 3, and need to be able to change the collision width and height of the wall tiles to something other than the width of the images, but I can't find anything that doesn't involve Tiled, which I can't use as it's a procedurally generated game.
I found a method to change the size of a tile, and I know how to get and individual tile, but nothing to change the collision size, and the few leads I found involved the differenced between the deprecated createDynamicLayer and createStaticLayer methods. The physics property of the tile object is empty, and doesn't contain the physics body of the tile, even though I set up collision between the wall tiles and the player (arcade physics). Any suggestions? thanks!
If you don't want to use the greate application "Tiled", the easiest option would be to set the tiles that should have a partial collision to not collide, and than iterate over the Map tiles and place invisible static physics bodies ontop.
It is maybe not very elegant, but it works well, and if you don't have > 1000 partial tiles on Screen, this should not be a performance issue.
Here is a Demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536 /8,
height: 42,
zoom: 4.5,
physics: {
default: 'arcade',
arcade: {
gravity:{ y: 0 },
debug: false
}
},
scene: {
create,
update
},
banner: false
};
function create () {
let graphics = this.make.graphics();
graphics.fillStyle(0x00ff00);
graphics.fillRect(8, 0, 8, 8);
graphics.fillStyle(0xff0000);
graphics.fillRect(16, 0, 8, 8);
graphics.fillStyle(0xff0000);
graphics.fillRect(24, 0, 8, 8);
graphics.generateTexture('tiles', 8*4, 8);
var level = [
[1,1,1,1,1],
[1,0,0,0,1],
[1,0,3,0,1],
[1,0,0,0,1],
[1,1,1,1,1],
]
// Map for the first level
var map = this.make.tilemap({ data: level, tileWidth: 8, tileHeight: 8 });
var tiles = map.addTilesetImage('tiles');
var layer = map.createLayer(0, tiles, 0, 0);
layer.setCollision(1);
this.player = this.add.circle(16,16,4, 0xffffff)
.setDepth(2);
this.physics.add.existing(this.player);
this.physics.add.collider(layer, this.player);
let partialCollisions = [];
map.forEachTile((tile) => {
if(tile.index == 3){
let partialCollition = this.add.circle(tile.pixelX + 4, tile.pixelY + 4, 1)
this.physics.add.existing(partialCollition, true);
partialCollisions.push(partialCollition)
}
});
this.physics.add.collider(partialCollisions, this.player);
this.keys = this.input.keyboard.createCursorKeys();
}
function update(){
let speed = 20;
this.player.body.setVelocity(0)
if(this.keys.up.isDown){
this.player.body.setVelocityY(-speed)
}
if(this.keys.down.isDown){
this.player.body.setVelocityY(speed)
}
if(this.keys.left.isDown){
this.player.body.setVelocityX(-speed)
}
if(this.keys.right.isDown){
this.player.body.setVelocityX(speed)
}
}
new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I'm writing a freehand drawing webapp using the HTML Canvas element. So far, I can draw shapes onto the sceeen that look like the following images.
I have stored all the points of the shapes into a JS array. For instance:
[
[
[118, 171],
[118, 170],
[118, 167],
...
],
[
[236, 131],
[236, 133],
[236, 135],
...
]
]
I'm now looking for a way to merge certain shapes, imagine that I would like to merge the two shapes in the following picture, here's how it would look like.
I think I have to redraw to the canvas but filter out all the points that are inside another shape.
The first idea that I had was to find a solution to check if a specific point was contained inside another shape and if it's the case, skip it. However, that would probably not work since moveTo/lineTo/stroke would create a line between the last independant point before a shape and the first independant after a shape.
I've looked up compositing operations that might be able to help, but haven't found a way to implement it yet.
How could I approach this feature ?
Input
Output
The following code is not a complete solution. It uses Path2D objects (still marked as an "experimental technology" by MDN) and the isPointInPath() canvas function.
// Canvas boilerplate
const canvas = document.querySelector('#mycanvas');
const ctx = canvas.getContext('2d');
// Create our shapes
const shape1 = [[100, 100], [70, 200], [150, 250], [300, 250], [300, 100], [150, 50]];
const shape2 = [[60, 60], [60, 160], [110, 210], [260, 210], [260, 60], [110, 10]];
// Create Path2D objects from our shapes
let p1 = new Path2D();
p1.moveTo(...shape1[0]);
for (let i = 1; i < shape1.length; i++) {
p1.lineTo(...shape1[i]);
}
p1.closePath();
let p2 = new Path2D();
p2.moveTo(...shape2[0]);
for (let i = 1; i < shape2.length; i++) {
p2.lineTo(...shape2[i]);
}
p2.closePath();
// Draw the shapes onb the canvas
ctx.fillStyle = 'white';
ctx.lineWidth = 4;
ctx.strokeStyle = 'green';
ctx.stroke(p1);
ctx.strokeStyle = 'blue';
ctx.stroke(p2);
// Just for this demo, fill the shapes to make them look joined together
ctx.fill(p2);
ctx.fill(p1);
// Discover whether coordinate points are inside/outside the other shape
let inside = [],
outside = [];
for (let i = 0; i < shape2.length; i++) {
if (ctx.isPointInPath(p1, ...shape2[i])) inside.push(shape2[i]);
else outside.push(shape2[i]);
}
for (let i = 0; i < shape1.length; i++) {
if (ctx.isPointInPath(p2, ...shape1[i])) inside.push(shape1[i]);
else outside.push(shape1[i]);
}
// Display coordinates inside
ctx.fillStyle = 'red';
for (let i = 0; i < inside.length; i++) {
ctx.beginPath();
ctx.moveTo(...inside[i]);
ctx.arc(...inside[i], 5, 0, 2 * Math.PI);
ctx.fill();
}
// ... and outside
ctx.fillStyle = 'black';
for (let i = 0; i < outside.length; i++) {
ctx.beginPath();
ctx.moveTo(...outside[i]);
ctx.arc(...outside[i], 5, 0, 2 * Math.PI);
ctx.fill();
}
<canvas id="mycanvas"></canvas>
To calculate a third shape which combines the coordinates of a path outlining the merged shape you need to work out which lines in each shape intersect, and where, then combine those new coordinates with your existing outside coordinates in the right order. Best of luck!
So I have sprites that I want to connect using p2.js' revolute constraints. My current implementation applys force to the sprites as soon as the constraint is created.
How can I avoid this behavior?
If it can't be avoided is there another way to connect 2 sprites with each other horizontally?EDIT:
var Game = {
preload: function() {
game.load.image('tree00', './imgs/tree/tree-00.png');
game.load.image('tree01', './imgs/tree/tree-01.png');
game.load.image('tree02', './imgs/tree/tree-02.png');
game.load.image('tree03', './imgs/tree/tree-03.png');
game.load.image('tree04', './imgs/tree/tree-04.png');
game.load.image('tree05', './imgs/tree/tree-05.png');
game.load.spritesheet('present', './imgs/dude.png', 32, 48);
},
create: function() {
game.physics.startSystem(Phaser.Physics.P2JS);
game.physics.p2.gravity.y = 300;
game.physics.startSystem(Phaser.Physics.ARCADE);
game.stage.backgroundColor = '#aaffee';
treeCollsionGroup = game.physics.p2.createCollisionGroup();
presentCollisionGroup = game.physics.p2.createCollisionGroup();
this.createPresent(game.world.width * 0.21, game.world.height * 0.6);
this.createTree(6, game.world.width * 0.2, game.world.height * 0.8);
//presentCollisionGroup.collides(treeCollsionGroup);
connection[0] = game.physics.p2.createRevoluteConstraint(treeParts[treeParts.length - 1], [(treeParts[treeParts.length - 1].width)/2, treeParts[treeParts.length - 1].height], present, [-present.width/2, treeParts[treeParts.length - 1].height], maxForce);
connection[1] = game.physics.p2.createRevoluteConstraint(treeParts[treeParts.length - 1], [(treeParts[treeParts.length - 1].width)/2, 0], present, [-present.width/2, 0], maxForce);
},
createTree: function(length, xAnchor, yAnchor) {
var lastSprite;
for (var i = 0; i < length; i++) {
newSprite = game.add.sprite(xAnchor, yAnchor - i*100, 'tree0' + i);
newSprite.scale.x = game.world.width/1920;
newSprite.scale.y = game.world.width/1920;
game.physics.p2.enable(newSprite, true);
if (i != length-1) {
newSprite.body.setRectangle(game.world.width * 0.10, newSprite.height * 0.15);
} else {
newSprite.body.setRectangle(newSprite.width * 0.8, newSprite.height * 0.8);
}
newSprite.body.setCollisionGroup(treeCollsionGroup);
if(i === 0) {
newSprite.body.static = true;
}
if (lastSprite) {
switch(i) {
case 1: constraint = game.physics.p2.createRevoluteConstraint(newSprite, [0, 0], lastSprite, [0, -lastSprite.height * 0.62], maxForce);
treeConstraints.push(constraint);
break;
case 2: constraint = game.physics.p2.createRevoluteConstraint(newSprite, [0, 0], lastSprite, [0, -lastSprite.height * 0.285], maxForce);
treeConstraints.push(constraint);
break;
case 3: constraint = game.physics.p2.createRevoluteConstraint(newSprite, [0, 0], lastSprite, [0, -lastSprite.height * 0.425], maxForce);
treeConstraints.push(constraint);
break;
case 4: constraint = game.physics.p2.createRevoluteConstraint(newSprite, [0, 0], lastSprite, [0, -lastSprite.height * 0.4], maxForce);
treeConstraints.push(constraint);
break;
case 5: constraint = game.physics.p2.createRevoluteConstraint(newSprite, [0, 0], lastSprite, [0, -lastSprite.height * 0.55], maxForce);
treeConstraints.push(constraint);
break;
}
}
lastSprite = newSprite;
treeParts.push(newSprite);
newSprite.body.collides(treeCollsionGroup);
}
},
createPresent: function(xAnchor, yAnchor) {
present = game.add.sprite(game.world.width * 0.21, game.world.height * 0.6, 'present');
game.physics.p2.enable(present, true);
present.scale.x = game.world.width/1920;
present.scale.y = game.world.width/1920;
present.body.setRectangle(present.width, present.height);
present.body.data.gravityScale = 0;
present.body.setCollisionGroup(presentCollisionGroup);
}
}
I cut the less important code out so it would not be too much (it already is). Basically what I'm doing is: I create a tree and connecting the parts using revolute constraints so they behave like a tree in the real world (for example in the wind).
Than I create the present which is basically a sprite that should be horizontally connected to the top of the tree. Therefore I use 2 revolute constraint one for the topmost point between the sprites and one for the bottommost. (I know it's kind of dirty code)
After I create these constraints and the present gets connected to the top of the tree the tree starts shaking and collapses (like it should). But I don't want this behaviour.Maybe a lock constraint is what I'm looking for, I have to look into this.
Edit 2:
After taking a look at lock constraints I realized that this is what I'm looking for. But even lock constraints are collapsing the tree.
I can't really understand your issue but have you tried Prismatic or even Lock Constraint? Can give us some code or even codepen example so we may be able to help you better?