How to make a sprite moving at the same speed of tileSprite in Phaser3 - phaser-framework

I am new in Phaser.
I want to make a background which represent the ground moving and there should be a bunch of rocks above it which I made them as a sprite group.
I made the ground as a tileSprite, and on each update I changed the tilePositionX. my problem is how to set the velocity of the rocks to match the update in the background so they appear to be on the ground and moving at the same speed of the ground.

theoretically you could measure the passed time, from the last update function call, and calculate the difference, or just eye-ball the needed velocity. (aka. try different velocities until it matches up with the background-movement):
Update:
If no physics object is needed you could move the "rock" "manually", this is very easy.
Here a quick demo, that I eye-balled:
The red mushroom, uses physics and velocity. Warning: the speed of the object can/will vary depending on the browser and hardware.
Update: The green mushroom, is moved manually via the position.
// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";
var config = {
type: Phaser.AUTO,
width: 536,
height: 150,
physics:{
default: 'arcade',
arcade: { debug: true }
},
scene: {
preload,
create,
update
}
};
var tilesprite;
var redRock;
var greenRock;
function preload ()
{
this.load.image('mushroom', 'https://labs.phaser.io/assets/sprites/mushroom16x16.png');
}
function create ()
{
tilesprite = this.add.tileSprite(400, 300, 800, 600, 'mushroom');
redRock = this.add.image(400, 40, 'mushroom').setScale(2);
redRock.setTint(0xff0000);
this.physics.add.existing(redRock);
redRock.body.setVelocityX(-60)
greenRock = this.add.image(400, 90, 'mushroom').setScale(2);
greenRock.setTint(0x00ff00);
}
function update (time, delta){
tilesprite.tilePositionX += 1;
let speedCorrection = (1000/60)/delta;
redRock.body.setVelocityX(-60 * speedCorrection )
greenRock.x -= 1;
// extra "reset" Rock
if( redRock.x + 16 < 0 ){
redRock.x = this.sys.game.canvas.width + 16;
greenRock.x = this.sys.game.canvas.width + 16;
}
}
var game = new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js">
</script>
Disclaimer: It is not the most elegant solution, but it took me literally 30 Seconds to find a matching velocity.
Minor Update:
I improved the eye-ball-method with a speed correction, it can cause minor flickering/slipping(max 1-2 pixel skips), but should move constant on "all" device.
The change is just adding a small calculation let speedCorrection = (1000/60)/delta;

Related

phaser.io how to draw over a path

I need to write a game like: https://robowhale.com/html5/drawing-letters/ with phaser.io library. I mean user must follow a path and draw for example letter "A".
basically, need to draw over a path, I checked almost all examples and tutorials, But couldn't find any proper tutorial or algorithm.
any help, link, source code or tutorial can helps me to figure out algorithm and start project.
Usually you will never find the full solution, you will have to merge multiple.
Here ist how I would approach this task (a quick and dirty solution):
Step 1)
Find an Example that solves a part of the problem and work from there
(Based on the example Quadratic Bezier Curve)
Then I :...
I removed the tween
added Mouse Input
split the path in segments
calculate until where the path should be draw
draw path segments
... And slowly adding missing features:
just update path when close enough
just allow move forwards
...
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: {
create: create,
update: update
}
};
var path;
var curve;
var graphics;
var game = new Phaser.Game(config);
var _myMaxPointIndex = 6;
function create() {
graphics = this.add.graphics();
path = { t: 0, vec: new Phaser.Math.Vector2() };
var startPoint = new Phaser.Math.Vector2(100, 500);
var controlPoint1 = new Phaser.Math.Vector2(50, 100);
var endPoint = new Phaser.Math.Vector2(700, 500);
curve = new Phaser.Curves.QuadraticBezier(startPoint, controlPoint1, endPoint);
}
function _myDrawPath(g, points) {
let startPoint = points.shift();
graphics.lineStyle(30, 0x0000ff, 1);
g.beginPath();
g.moveTo(startPoint.x, startPoint.y);
let maxPointsToDraw = _myMaxPointIndex == -1 ? points.length : _myMaxPointIndex + 1;
for (let index = 0; index < maxPointsToDraw; index++) {
const point = points[index];
g.lineTo(point.x, point.y);
}
g.strokePath();
}
function update() {
graphics.clear();
graphics.lineStyle(2, 0x00ff00, 1);
curve.draw(graphics);
// get 20 Point from the Curve (can be more if to jaggy)
let _myPoints = curve.getPoints(20);
_myDrawPath(graphics, _myPoints)
if (this.input.activePointer.isDown) {
// Here I update the Max point that should be draw
let _myMouse = this.input.activePointer.position;
let _myNearestPoint = _myPoints.reduce((p, c, i) => {
let distance = Phaser.Math.Distance.BetweenPoints(_myMouse, c)
if (p.distance == -1 || p.distance > distance) {
p.distance = distance
p.idx = i
}
return p
}, { distance: -1 })
_myMaxPointIndex = _myNearestPoint.idx
}
}
h1 {
font-family:arial
}
#phaser-example{
transform: translate(-20%, -20%) scale(.5);
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
<h1>Click to calculate path</H1>
<div id="phaser-example"></div>
And with a bit of luck:
While building this solution, I had to "google" for some documentation details, and found this in a Phaser forum, that points to a interesting solution with a working CodePen, with a more complex full working example (Just adding the codepen link if the forum entry gets deleted).

PhaserJS: After Rotation of camera dragging a Sprite gives strange coords

Basically the problem is that after you rotate the camera, the points that are given as arguments in the callback for dragging are not what I expected. I'm guessing I have to Rotate the given points also but I just couldn't.
Can Someone explain what is going on, is this some kind of bug or what should I do in order the sprite to follow the mouse cursor?
Easiest way to explain the problem is to reproduce it:
1) Go to Phaser Example Runner
2) Copy- Paste this code:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
function create ()
{
var image = this.add.sprite(200, 300, 'eye').setInteractive();
this.cameras.main.setRotation(Math.PI);
image.on('pointerover', function () {
this.setTint(0x00ff00);
});
image.on('pointerout', function () {
this.clearTint();
});
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject) {
gameObject.setTint(0xff0000);
});
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
console.log(`x: ${dragX}, y: ${dragY}`);
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function (pointer, gameObject) {
gameObject.clearTint();
});
}
3) Open the console, drag around the Eye and look at what coordinates are given.
4) If you remove line 24 (the rotation of the camera) Everything works as expected.
(The example is taken from Phaser 3 Official examples and a bit changed for the bug)
According to Phaser's API Documentation on the setRotation() method, the rotation given in radians applies to everything rendered by the camera. Unfortunately, your pointer isn't rendered by the camera so it doesn't get the same rotated coordinates. Not sure if this is a bug with the library or just a poorly documented exception, but I believe there is a workaround.
Create 2 variables to hold an initial position and a final position:
var image = this.add.sprite(200, 300, 'eye').setInteractive();
var initial = [];
var final = [];
Populate the initial position in your .on('dragstart') method:
this.input.on('dragstart', function (pointer, gameObject) {
initial = [
gameObject.x,
gameObject.y,
pointer.x,
pointer.y
];
gameObject.setTint(0xff0000);
});
Then, populate the final variable in your .on('drag') method:
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
final = [
gameObject.x, // not necessary but keeping for variable shape consistency
gameObject.y, // not necessary but keeping for variable shape consistency
pointer.x,
pointer.y
];
gameObject.x = initial[0] + (initial[2] - final[2]);
gameObject.y = initial[1] + (initial[3] - final[3]);
});
All we're doing here is keeping track of the change in pointer position and mimicking that change in our gameObject.

How to change z-index on sprite properly?

I have google it and I know that properly way to add z-index is by order of creating but I have different situation.
I'm creating card game and I want to move card on click and after that card should be on top which is not possible so I have solved in following way.
In function which is called on card click I'm destroying that card and creating identically new card which is on top because it is created last.
Is there another way of solving this situation?
Thank you
On card release you could use BringToTop (see also moveDown, moveUp and sendToBack methods that can be usefull to you)
Something like:
game.world.bringToTop(activeCard);
After this line, activeCard should be on top of all others sprites or groups.
if the objects/sprites are not in the same group game.world.bringToTop(target) will not work.
a more solid solution is to add objects to groups in the order you want them to be layered like so:
// Groups for drawing layers
var back_layer = game.add.group();
var mid_layer = game.add.group();
var front_layer = game.add.group();
// It doesn't matter what order you add things to these groups, the draw order will be back, mid, front (unless you change it...)
back_layer.create(0, 0, "bg");
front_layer.create(0, 0, "front");
mid_layer.create(300, 200, "object1");
mid_layer.create(500, 400, "object2");
explained here - www.html5gamedevs.com post
Personally I worked with both solutions and the groups one proved to be much more workable as the project starts to scale
hope this helps
You can test ordering with these;
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
game.global = {};
function preload () {
}
function create () {
game.physics.startSystem(Phaser.Physics.ARCADE);
game.stage.backgroundColor = '#01555f';
this.gfx = game.add.graphics(0, 0);
this.gfx.visible = false;
this.gfx.beginFill(0x02C487, 1);
this.gfx.drawRect(100, 100, 250, 1);
this.barSprite = game.add.sprite(100, 500, this.gfx.generateTexture());
this.barSprite.anchor.y = 1;
game.add.tween(this.barSprite).to({ height: 400 }, 1000, Phaser.Easing.Default, true, 0);
var bubbleGfx = game.add.graphics(0, 0);
bubbleGfx.lineStyle(2 * 1, 0x000000, 1);
bubbleGfx.visible = true;
bubbleGfx.beginFill(0xffffff, 1);
bubbleGfx.drawRoundedRect(300, 150, 200, 100, 8);
this.gfx2 = game.add.graphics(0, 0);
this.gfx2.visible = false;
this.gfx2.beginFill(0x02C111, 1);
this.gfx2.drawRect(150, 100, 250, 1);
this.barSprite2 = game.add.sprite(400, 500, this.gfx2.generateTexture());
this.barSprite2.anchor.y = 1;
game.add.tween(this.barSprite2).to({ height: 400 }, 1000, Phaser.Easing.Default, true, 0);
}
function update () {
}

Drag and zoom text with Kineticjs

I am trying to zoom and pan a text which is draggable already. All the examples are on images or shapes and it seems I cannot adapt it to a text object. My questions are:
Do I have to use the anchors or is any simpler way zoom a text with Kineticjs?
I found an example regarding zooming a shape and the code crashes here:
var layer = new Kinetic.Layer({
drawFunc : drawTriangle //drawTriangle is a function defined already
});
Can we call a function while we are creating a layer?
I usually create a layer and then add the outcome of the function in it.
Any idea would be great, thanks.
I thought of many ways you could do this but this is the one I ended up implementing: jsfiddle
Basically, you have an anchor (which doesn't always have to be there, you can hide and show it if you would like. Let me know if you need help with that) and if you drag the anchor down it increases the fontSize, and if you drag the anchor up it decreases the fontSize.
I followed the exact same anchor tutorial but instead I added a dragBoundFunc to limit dragging to the Y-axis:
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
And then I updated the updateAnchor() function to only detect the single anchor I added to the group named sizeAnchor:
var mY = 0;
function update(activeAnchor, event) {
var group = activeAnchor.getParent();
var sizeAnchor = group.get('.sizeAnchor')[0];
var text = group.get('.text')[0];
if (event.pageY < mY) {
text.setFontSize(text.getFontSize()-1);
} else {
text.setFontSize(text.getFontSize()+1);
}
sizeAnchor.setPosition(-10, 0);
mY = event.pageY;
}
Basically mY is used compared to the e.PageY to see if the mouse is moving up or down. Once we can determine the mouse direction, then we can decide if we should increase or decrease the fontSize!
Alternatively, you can use the mousewheel to do the exact same thing! I didn't implement it myself but it's definitely doable. Something like:
Mousewheel down and the fontSize decreases
Mousewheel up and the fontSize increases
Hopefully this emulates "Zooming" a text for you. And I guess being able to drag the text acts as "panning" right?
UPDATE (based on comment below)
This is how you would limit dragging to the Y-Axis using dragBoundFunc:
var textGroup = new Kinetic.Group({
x: 100,
y: 100,
draggable: true,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
See the updated jsfiddle (same jsfiddle as above)

Is it possible to animate filter in Fabric.js?

Is it possible to animate the images filter in Fabric.js? Such as a "pixelate" filter.
I solved it in the same way like the demo.
Unfortunately filters aren't able to be animated - they need too much processing time.
Here's my Code:
image = ... //Image, where the filter should be applied
var filter = new fabric.Image.filters.RemoveWhite({
threshold: 0,
distance: 140
});
image.filters.push(filter);
image.applyFilters(canvas.renderAll.bind(canvas));
animate(image,1, 400); //Start the Animation
function animate(image,value, stop){
value += ((stop-value)*0.02); //Change the threshold-value
if (image.filters[0]) {
image.filters[0]['threshold'] = value;
console.log(value);
image.applyFilters(canvas.renderAll.bind(canvas)); //Start creating the new image
if(value<stop-100){
setTimeout(function(){act(image,value,stop);},1);
}
}
}
I know the code isn't the most efficient one, but it works. And you can see that Animating filters consumes too much time.
(I tested it with a 1920x1080px image, maybe you can use it with smaller images)
Here is a updated version for the brightness filter
var brightnessValue = 0.9;
var brightnessFilter = new fabric.Image.filters.Brightness({
brightness: brightnessValue
});
fabricImage.filters.push(brightnessFilter);
fabric.util.requestAnimFrame(function brightnessFilterAnimation() {
brightnessValue = brightnessValue - 0.04;
brightnessFilter.brightness = brightnessValue;
fabricImage.applyFilters();
if (brightnessValue > 0) {
fabric.util.requestAnimFrame(brightnessFilterAnimation);
}
});

Resources