How to create sprite animation from particles animation by means of tweens? - javascript

Here is such a code snippet:
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create });
var emitter;
function preload() {
game.load.image('wasp', 'assets/glass.png');
game.load.image('glass', 'assets/glass.png');
game.load.image('water', 'assets/blue-raster-floor.png');
}
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
game.add.tileSprite(0, 344, 800, 256, 'water');
emitter = game.add.emitter(game.world.centerX, 200);
emitter.makeParticles('glass');
emitter.setXSpeed(-200, 200);
emitter.setYSpeed(-150, -250);
emitter.bringToTop = true;
emitter.setAlpha(0.1, 1, 500);
emitter.setScale(-2, 2, 1, 1, 3000, Phaser.Easing.Sinusoidal.InOut, true);
emitter.gravity = 300;
emitter.start(false, 5000, 700, 50);
game.time.events.add(3000, destroyEmitter, this);
}
function tweens(cash) {
var bugs;
var index = 0;
var data;
var pos = [];
var tween;
var tweenData = { x: 0, y: 0 };
tween = game.make.tween(tweenData).to( { x: 100, y: 400 }, 2000, "Sine.easeInOut");
tween.yoyo(true);
data = tween.generateData(60);
bugs = game.add.group();
pos.push(new Phaser.Point(32, 0));
pos.push(new Phaser.Point(300, 100));
pos.push(new Phaser.Point(600, 70));
bugs.create(pos[0].x, pos[0].y, 'wasp');
bugs.create(pos[1].x, pos[1].y, 'wasp');
bugs.create(pos[2].x, pos[2].y, 'wasp');
tween.onUpdateCallback(function () {
bugs.getAt(0).x = pos[0].x + data[index].x;
bugs.getAt(0).y = pos[0].y + data[index].y;
bugs.getAt(1).x = pos[1].x + (data[index].x / 2);
bugs.getAt(1).y = pos[1].y + data[index].y;
// Inverse one of the values
bugs.getAt(2).x = pos[2].x - data[index].x;
bugs.getAt(2).y = pos[2].y + data[index].y;
index++;
if (index === data.length)
{
index = 0;
}
});
tween.start();
}
function destroyEmitter() {
console.log(emitter);
emitter.destroy();
tweens();
}
As you can see, I have made the particle-animation. Such steps need to be taken:
Particle-animation should be cached in the form of a set of shots (textures)
Particle-animation should be deleted. I have already done it (by means of ‘destroy‘)
Instead of the particle animation sprite animation should be realized by means of the function tweens using received textures
and passing these textures as the argument of the function tweens
Any refractoring is welcome.

In Phaser, the emitter particles are of the relatively simple DisplayObject class which do not support animations like the Phaser.Sprite does. Btw I don't know if using tweens is the best way to animate particles, because I suspect it will be heavy on CPU usage, using Sprite animations on the other hand is a bit more "light weight".
But either way, you could create a custom particle class which contains the code for your particle animation (using tweens, animations, timers, whatever) and then set that custom class as the emitter.particleClass, see a code example in link below:
http://codetuto.com/2016/02/phaser-animated-particles/

Related

Phaser 3 how to change gravity when the player jumps

I am developing an arcade game in Phaser 3, the problem is that the player sprite is dropped from the top of the screen when the game loads and I don't want that, I want him to be rendered without falling so I set the y gravity to 0 in order to achieve that. That works, however now my player cannot jump, I am trying to reset the gravity to 300 on keyDown but that isn't working, how can I achieve that? I tried to set the y gravity to 300 again in the create function but that didn't work too is it possible?
Here is my code:
// let gravity = 0
let config = {
type: Phaser.AUTO,
width: 800,
height: 500,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: false
}
},
scene: {
preload: preload,
create: create,
update: update
},
scale: {
mode: Phaser.Scale.FIT,
parent: 'root',
autoCenter: Phaser.Scale.CENTER_BOTH,
width: 800,
height: 600
},
};
new Phaser.Game(config)
function preload() {
this.load.image('sky', require('../assets/backgrounds/sky.png'));
this.load.image('jungle', require('../assets/backgrounds/jungle.png'));
this.load.image('ground', require('../assets/tiles/ground-transp.png'))
this.load.image('small-platform', require("../assets/tiles/small-platform-removebg-preview.png"))
this.load.image('jungle-platform', require("../assets/tiles/jungle-platform.png"))
this.load.image('large-platform', require("../assets/tiles/large-platform-removebg-preview.png"))
this.load.image('tree', require("../assets/backgrounds/treetrunk.png"))
this.load.image('plant', require("../assets/backgrounds/plant.png"))
this.load.image('plant2', require("../assets/backgrounds/plants2.png"))
this.load.image('rock', require("../assets/backgrounds/rock.png"))
this.load.atlas('sacred', require('../assets/spritesheets/sacredRock.png'), require('../assets/spritesheets/sacredRock.json'))
this.load.atlas('player', require('../assets/spritesheets/dilopodon.png'), require('../assets/spritesheets/dilopodon.json'))
this.load.tilemapTiledJSON('Ground', require('../assets/maps/simple-tutorial.json'));
}
function create () {
this.bg = this.add.image(-41, -41, 'sky');
this.bg = this.add.image('jungle');
this.add.image(67, 370, 'tree')
this.add.image(167, 429, 'plant')
this.add.image(700, 405, 'plant2')
this.add.image(300, 440, 'rock')
const map = this.make.tilemap({ key: 'Ground' })
// Creating tilesets
const groundTileSet = map.addTilesetImage('Ground', 'ground')
const platformTileset = map.addTilesetImage('small-platform', 'small-platform')
const junglePlatformTileset = map.addTilesetImage('jungle-platform', 'jungle-platform')
const largePlatformTileset = map.addTilesetImage('large-platform', 'large-platform')
let groundLayer = map.createLayer('Ground', [groundTileSet, platformTileset, junglePlatformTileset, largePlatformTileset])
groundLayer.setCollisionByExclusion([-1]);
// Creating the Player
player = this.physics.add.sprite(100, 420, 'player')
player.setBounce(0.2);
player.setCollideWorldBounds(true)
player.body.width = 60
player.body.height = 60
player.body.offset.x = 10
player.body.offset.x = 10
// Creating the Sacred Stone
sacredStone = this.physics.add.sprite(400, 270, 'sacred')
sacredStone.setCollideWorldBounds(true)
sacredStone.body.width = 60
sacredStone.body.height = 230
//Physics
this.physics.add.collider(groundLayer, player )
this.physics.add.collider(groundLayer, sacredStone )
// Debug graphics
// let graphics = this.add.graphics()
// groundLayer.renderDebug(graphics, {
// tileColor: new Phaser.Display.Color(0, 0, 255, 50), // Non-colliding tiles
// collidingTileColor: new Phaser.Display.Color(0, 255, 0, 100), // Colliding tiles
// faceColor: new Phaser.Display.Color(255, 0, 0, 100) // Colliding face edges
// });
// let frameNames = this.textures.get('player').getFrameNames();
function update() {
sacredStone.anims.play('glow', true)
if (cursors.left.isDown)
{
player.setVelocityX(-160);
player.anims.play('walkLeft', true);
}
else if (cursors.right.isDown)
{
player.setVelocityX(160);
player.anims.play('walkRight', true)
}
else
{
player.setVelocityX(0);
player.anims.play('idle', true);
}
if (cursors.up.isDown && player.body.blocked.down)
{
config.physics.arcade.gravity.y = 300
player.setVelocityY(-330);
}
}
I think the problem is, that when you set the position of the player in the game, you are setting it to low. When two gameObject within arcade physics overlap, they can't collide anymore, so they fall through.
I would set the gravity again, and than just set the position of the player just a few pixels higher -10 might be enough. If it still falls through set it higher until it works. I think the sacredStone has the same issue.

Phaser 3 - bounce back sprite on collision with object

In Phaser3, how do you make a sprite bounce back when it collides with an object? At the moment, I can detect a collision, but I want the car to bounce back when it collides.
My code:
import Phaser from 'phaser';
const config = {
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
scene: {
preload: preload,
create: create,
update: update,
render: render
}
};
const game = new Phaser.Game(config);
let platform;
let player;
let cursors;
function preload() {
this.load.image('car', 'https://labs.phaser.io/assets/sprites/car90.png')
this.load.image('sky', 'https://labs.phaser.io/assets/skies/gradient11.png');
this.load.image('ground', 'https://labs.phaser.io/assets/sprites/platform.png');
}
function create() {
this.add.image(400, 300, 'sky');
platform = this.physics.add.image(400, 400, 'ground');
platform.body.setBounce(20, 20);
platform.setImmovable(true);
player = this.physics.add.sprite(400, 300, 'car', 1);
player.body.setBounce(20, 20);
player.setCollideWorldBounds(true);
cursors = this.input.keyboard.createCursorKeys();
this.physics.add.collider(player, platform);
}
function update() {
player.body.velocity.x = 0;
player.body.velocity.y = 0;
player.body.angularVelocity = 0;
if (cursors.left.isDown) {
player.body.angularVelocity = -40;
}
if (cursors.right.isDown) {
player.body.angularVelocity = 40;
}
if (cursors.up.isDown) {
this.physics.velocityFromRotation(player.rotation, 150, player.body.velocity);
}
if (cursors.down.isDown) {
this.physics.velocityFromRotation(player.rotation, -150, player.body.velocity);
}
}
function render() {
}
Stackblitz: https://stackblitz.com/edit/phaser3-typescript-ctun9e
Firstly, your velocity is being reset to 0 every frame, and reset to a static value depending on the keyboard input. Bounce is an event that alters an object's body's velocity, so resetting this velocity every update frame will make it look like set bounce isn't working.
Secondly, set bounce expects a float between 0 and 1, it looks like you can set it higher for a collision that reflects faster than the incoming speed, but 20 is far too high, once it collides with a value higher than 1, the sprite starts colliding with all the world bounds at ever-increasing speeds.
Linked a fork of your stackblitz with the set bounce at 1 and removing the reset of velocity when keys are not pressed.
Stackblitz

Prevent force-dragging bodies through other bodies with MatterJS

I'm using MatterJs for a physics based game and have not found a solution for the problem of preventing bodies being force-dragged by the mouse through other bodies. If you drag a body into another body, the body being dragged can force itself into and through the other body. I'm looking for a reliable way to prevent them from intersecting. You can observe this effect in any MatterJS demo by selecting a body with the mouse, and trying to force it through another body. Here is a typical example:
https://brm.io/matter-js/demo/#staticFriction
Unfortunately this breaks any games or simulations depending on drag-and-drop.
I have attempted numerous solutions, such as breaking the mouse constraint when a collision occurs, or reducing constraint stiffness, but nothing which works reliably.
Any suggestions welcome!
I think that the best answer here would be a significant overhaul to the Matter.Resolver module to implement predictive avoidance of physical conflicts between any bodies. Anything short of that is guaranteed to fail under certain circumstances. That being said here are two "solutions" which, in reality, are just partial solutions. They are outlined below.
Solution 1   (Update)
This solution has several advantages:
It is more concise than Solution 2
It creates a smaller computational footprint than Solution 2
The drag behavior is not interrupted the way it is in Solution 2
It can be non-destructively combined with Solution 2
The idea behind this approach is to resolve the paradox of what happens "when an unstoppable force meets an immovable object" by rendering the force stoppable. This is enabled by the Matter.Event beforeUpdate, which allows the absolute velocity and impulse (or rather positionImpulse, which isn't really physical impulse) in each direction to be constrained to within user-defined bounds.
window.addEventListener('load', function() {
var canvas = document.getElementById('world')
var mouseNull = document.getElementById('mouseNull')
var engine = Matter.Engine.create();
var world = engine.world;
var render = Matter.Render.create({ element: document.body, canvas: canvas,
engine: engine, options: { width: 800, height: 800,
background: 'transparent',showVelocity: true }});
var body = Matter.Bodies.rectangle(400, 500, 200, 60, { isStatic: true}),
size = 50, counter = -1;
var stack = Matter.Composites.stack(350, 470 - 6 * size, 1, 6,
0, 0, function(x, y) {
return Matter.Bodies.rectangle(x, y, size * 2, size, {
slop: 0, friction: 1, frictionStatic: Infinity });
});
Matter.World.add(world, [ body, stack,
Matter.Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Matter.Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
Matter.Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
Matter.Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);
Matter.Events.on(engine, 'beforeUpdate', function(event) {
counter += 0.014;
if (counter < 0) { return; }
var px = 400 + 100 * Math.sin(counter);
Matter.Body.setVelocity(body, { x: px - body.position.x, y: 0 });
Matter.Body.setPosition(body, { x: px, y: body.position.y });
if (dragBody != null) {
if (dragBody.velocity.x > 25.0) {
Matter.Body.setVelocity(dragBody, {x: 25, y: dragBody.velocity.y });
}
if (dragBody.velocity.y > 25.0) {
Matter.Body.setVelocity(dragBody, {x: dragBody.velocity.x, y: 25 });
}
if (dragBody.positionImpulse.x > 25.0) {
dragBody.positionImpulse.x = 25.0;
}
if (dragBody.positionImpulse.y > 25.0) {
dragBody.positionImpulse.y = 25.0;
}
}
});
var mouse = Matter.Mouse.create(render.canvas),
mouseConstraint = Matter.MouseConstraint.create(engine, { mouse: mouse,
constraint: { stiffness: 0.1, render: { visible: false }}});
var dragBody = null
Matter.Events.on(mouseConstraint, 'startdrag', function(event) {
dragBody = event.body;
});
Matter.World.add(world, mouseConstraint);
render.mouse = mouse;
Matter.Engine.run(engine);
Matter.Render.run(render);
});
<canvas id="world"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.10.0/matter.js"></script>
In the example I am restricting the velocity and positionImpulse in x and y to a maximum magnitude of 25.0. The result is shown below
As you can see, it is possible to be quite violent in dragging the bodies and they will not pass through one another. This is what sets this approach apart from others: most other potential solutions fail when the user is sufficiently violent with their dragging.
The only shortcoming I have encountered with this method is that it is possible to use a non-static body to hit another non-static body hard enough to give it sufficient velocity to the point where the Resolver module will fail to detect the collision and allow the second body to pass through other bodies. (In the static friction example the required velocity is around 50.0, I've only managed to do this successfully one time, and consequently I do not have an animation depicting it).
Solution 2
This is an additional solution, fair warning though: it is not straightforward.
In broad terms the way this works is to check if the body being dragged, dragBody, has collided with a static body and if the mouse has since moved too far without dragBody following. If it detects that the separation between the mouse and dragBody has become too large it removes the Matter.js mouse.mousemove event listener from mouse.element and replaces it with a different mousemove function, mousemove(). This function checks if the mouse has returned to within a given proximity of the center of the body. Unfortunately I couldn't get the built-in Matter.Mouse._getRelativeMousePosition() method to work properly so I had to include it directly (someone more knowledgeable than me in Javascript will have to figure that one out). Finally, if a mouseup event is detected it switches back to the normal mousemove listener.
window.addEventListener('load', function() {
var canvas = document.getElementById('world')
var mouseNull = document.getElementById('mouseNull')
var engine = Matter.Engine.create();
var world = engine.world;
var render = Matter.Render.create({ element: document.body, canvas: canvas,
engine: engine, options: { width: 800, height: 800,
background: 'transparent',showVelocity: true }});
var body = Matter.Bodies.rectangle(400, 500, 200, 60, { isStatic: true}),
size = 50, counter = -1;
var stack = Matter.Composites.stack(350, 470 - 6 * size, 1, 6,
0, 0, function(x, y) {
return Matter.Bodies.rectangle(x, y, size * 2, size, {
slop: 0.5, friction: 1, frictionStatic: Infinity });
});
Matter.World.add(world, [ body, stack,
Matter.Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Matter.Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
Matter.Bodies.rectangle(800, 300, 50, 600, { isStatic: true }),
Matter.Bodies.rectangle(0, 300, 50, 600, { isStatic: true })
]);
Matter.Events.on(engine, 'beforeUpdate', function(event) {
counter += 0.014;
if (counter < 0) { return; }
var px = 400 + 100 * Math.sin(counter);
Matter.Body.setVelocity(body, { x: px - body.position.x, y: 0 });
Matter.Body.setPosition(body, { x: px, y: body.position.y });
});
var mouse = Matter.Mouse.create(render.canvas),
mouseConstraint = Matter.MouseConstraint.create(engine, { mouse: mouse,
constraint: { stiffness: 0.2, render: { visible: false }}});
var dragBody, overshoot = 0.0, threshold = 50.0, loc, dloc, offset,
bodies = Matter.Composite.allBodies(world), moveOn = true;
getMousePosition = function(event) {
var element = mouse.element, pixelRatio = mouse.pixelRatio,
elementBounds = element.getBoundingClientRect(),
rootNode = (document.documentElement || document.body.parentNode ||
document.body),
scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset :
rootNode.scrollLeft,
scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset :
rootNode.scrollTop,
touches = event.changedTouches, x, y;
if (touches) {
x = touches[0].pageX - elementBounds.left - scrollX;
y = touches[0].pageY - elementBounds.top - scrollY;
} else {
x = event.pageX - elementBounds.left - scrollX;
y = event.pageY - elementBounds.top - scrollY;
}
return {
x: x / (element.clientWidth / (element.width || element.clientWidth) *
pixelRatio) * mouse.scale.x + mouse.offset.x,
y: y / (element.clientHeight / (element.height || element.clientHeight) *
pixelRatio) * mouse.scale.y + mouse.offset.y
};
};
mousemove = function() {
loc = getMousePosition(event);
dloc = dragBody.position;
overshoot = ((loc.x - dloc.x)**2 + (loc.y - dloc.y)**2)**0.5 - offset;
if (overshoot < threshold) {
mouse.element.removeEventListener("mousemove", mousemove);
mouse.element.addEventListener("mousemove", mouse.mousemove);
moveOn = true;
}
}
Matter.Events.on(mouseConstraint, 'startdrag', function(event) {
dragBody = event.body;
loc = mouse.position;
dloc = dragBody.position;
offset = ((loc.x - dloc.x)**2 + (loc.y - dloc.y)**2)**0.5;
Matter.Events.on(mouseConstraint, 'mousemove', function(event) {
loc = mouse.position;
dloc = dragBody.position;
for (var i = 0; i < bodies.length; i++) {
overshoot = ((loc.x - dloc.x)**2 + (loc.y - dloc.y)**2)**0.5 - offset;
if (bodies[i] != dragBody &&
Matter.SAT.collides(bodies[i], dragBody).collided == true) {
if (overshoot > threshold) {
if (moveOn == true) {
mouse.element.removeEventListener("mousemove", mouse.mousemove);
mouse.element.addEventListener("mousemove", mousemove);
moveOn = false;
}
}
}
}
});
});
Matter.Events.on(mouseConstraint, 'mouseup', function(event) {
if (moveOn == false){
mouse.element.removeEventListener("mousemove", mousemove);
mouse.element.addEventListener("mousemove", mouse.mousemove);
moveOn = true;
}
});
Matter.Events.on(mouseConstraint, 'enddrag', function(event) {
overshoot = 0.0;
Matter.Events.off(mouseConstraint, 'mousemove');
});
Matter.World.add(world, mouseConstraint);
render.mouse = mouse;
Matter.Engine.run(engine);
Matter.Render.run(render);
});
<canvas id="world"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.10.0/matter.js"></script>
After applying the event listener switching scheme the bodies now behave more like this
I have tested this fairly thoroughly, but I can't guarantee it will work in every case. It also bears noting that the mouseup event is not detected unless the mouse is within the canvas when it occurs - but this is true for any Matter.js mouseup detection so I didn't try to fix that.
If the velocity is sufficiently large, Resolver will fail to detect any collision, and since it lacks predictive prevention of this flavor of physical conflict, will allow the body to pass through, as shown here.
This can be resolved by combining with Solution 1.
One last note here, it is possible to apply this to only certain interactions (e.g. those between a static and a non-static body). Doing so is accomplished by changing
if (bodies[i] != dragBody && Matter.SAT.collides(bodies[i], dragBody).collided == true) {
//...
}
to (for e.g. static bodies)
if (bodies[i].isStatic == true && bodies[i] != dragBody &&
Matter.SAT.collides(bodies[i], dragBody).collided == true) {
//...
}
Failed solutions
In case any future users come across this question and find both solutions insufficient for their use case, here are some of the solutions I attempted which did not work. A guide of sorts for what not to do.
Calling mouse.mouseup directly: object deleted immediately.
Calling mouse.mouseup via Event.trigger(mouseConstraint, 'mouseup', {mouse: mouse}): overridden by Engine.update, behavior unchanged.
Making the dragged object temporarily static: object deleted on returning to non-static (whether via Matter.Body.setStatic(body, false) or body.isStatic = false).
Setting the force to (0,0) via setForce when approaching conflict: object can still pass through, would need to be implemented in Resolver to actually work.
Changing mouse.element to a different canvas via setElement() or by mutating mouse.element directly: object deleted immediately.
Reverting object to last 'valid' position: still allows pass through,
Change behavior via collisionStart: inconsistent collision detection still permits pass through with this method
I would have managed the feature in another way:
No "drag" (so no continuos align of dragpoint with offset Vs dragged object)
On mouseDown the mouse pointer position give an oriented velocity vector for object to follow
On mouseUp reset your velocity vector
Let the matter simulation do the rest
To control collision when dragged you need to utilize collision filter and events.
Create bodies with default collision filter mask 0x0001. Add catch startdrag and enddrag events and set different body collision filter category to temporarily avoid collisions.
Matter.Events.on(mouseConstraint, 'startdrag', function(event) {
event.body.collisionFilter.category = 0x0008; // move body to new category to avoid collision
});
Matter.Events.on(mouseConstraint, 'enddrag', function(event) {
event.body.collisionFilter.category = 0x0001; // return body to default category to activate collision
});
window.addEventListener('load', function () {
//Fetch our canvas
var canvas = document.getElementById('world');
//Setup Matter JS
var engine = Matter.Engine.create();
var world = engine.world;
var render = Matter.Render.create({
canvas: canvas,
engine: engine,
options: {
width: 800,
height: 800,
background: 'transparent',
wireframes: false,
showAngleIndicator: false
}
});
//Add a ball
const size = 50;
const stack = Matter.Composites.stack(350, 470 - 6 * size, 1, 6, 0, 0, (x, y) => {
return Matter.Bodies.rectangle(x, y, size * 2, size, {
collisionFilter: {
mask: 0x0001,
},
slop: 0.5,
friction: 1,
frictionStatic: Infinity,
});
});
Matter.World.add(engine.world, stack);
//Add a floor
var floor = Matter.Bodies.rectangle(250, 520, 500, 40, {
isStatic: true, //An immovable object
render: {
visible: false
}
});
Matter.World.add(world, floor);
//Make interactive
var mouseConstraint = Matter.MouseConstraint.create(engine, { //Create Constraint
element: canvas,
constraint: {
render: {
visible: false
},
stiffness: 0.8
}
});
Matter.World.add(world, mouseConstraint);
// add events to listen drag
Matter.Events.on(mouseConstraint, 'startdrag', function (event) {
event.body.collisionFilter.category = 0x0008; // move body to new category to avoid collision
});
Matter.Events.on(mouseConstraint, 'enddrag', function (event) {
event.body.collisionFilter.category = 0x0001; // return body to default category to activate collision
});
//Start the engine
Matter.Engine.run(engine);
Matter.Render.run(render);
});
<canvas id="world"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.10.0/matter.min.js"></script>
This seems to be related to issue 672 on their GitHub page which seems to suggest that this occurs due to a lack of Continuous Collision Detection (CCD).
An attempt to remedy this has been made and the code for it can be found here but the issue is still open so it looks like you might need to edit the engine to build CCD into it yourself.

HTML5 Canvas drawImage() inside object literal

I'm trying to make a snake game with HTML5 using the object literal pattern, but I can't seem to draw an image on the canvas. I've researched a lot and found for instance that I can't set the image src while the object is being created (so I've put that in a function). The image seems to be available as it shows up in the console and can be appended to the body. What am I missing please?
(function ($) {
$.fn.preload = function() { // http://stackoverflow.com/a/476681
this.each(function(){
$('<img/>')[0].src = this;
});
}
})(jQuery);
$(document).ready(function() {
$(['./images/grass-500x500.png']).preload(); // I've tried with and without this function (defined elsewhere)
// Object literal pattern
var game = {
// Background image
background: new Image(),
setBGSource: function() {
this.background.src = 'images/grass-500x500.png';
},
// Canvas details
canvas: $("#canvas")[0],
ctx: canvas.getContext("2d"),
WIDTH: $("#canvas").width(),
HEIGHT: $("#canvas").height(),
// Game details
CELL_WIDTH: 10,
direction: null,
food: null,
score: null,
snakeArray: [],
init: function() {
this.direction = "right";
this.createSnake();
this.setBGSource();
this.draw();
},
createSnake: function() {
var length = 5; // Initial length of snake
for (var i = length - 1; i >= 0; i--) {
this.snakeArray.push({
x: i,
y: 1 // y : 0 - initial position of snake in cell units
});
}
},
// Create food item
createFood: function() {
this.food = {
x: Math.round(Math.random() * (WIDTH - CELL_WIDTH) / CELL_WIDTH),
y: Math.round(Math.random() * (HEIGHT - CELL_WIDTH) / CELL_WIDTH)
} // Position of food with x and and y between 0 and e.g 44
},
// Drawing function
draw: function() {
// Repaint the background on each frame
console.log(this.background); // displays <img src="images/grass-500x500.png">
this.ctx.drawImage(this.background, 0, 0); // WHY DOESN'T THIS WORK PLEASE?
$('body').append(this.background); // appends image, no problem
}
};
game.init();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas"></canvas>
The problem here is that the image is being preloaded asynchronously while at the same time you call game.init() and thus game.draw(), which expects the image being loaded already.
Thus, unless the image is in your browser's cache, the asynchronous preloading might not have finished at the time of game.draw().
You need to wait until preloading has finished before calling game.init(). JavaScript offers some good tools in dealing with asynchronous execution, e.g. callbacks, promises etc.
Have a look here: https://gamedev.stackexchange.com/questions/24102/resource-loader-for-an-html5-and-javascript-game

Tiled map overlap detection not working properly

I am building a tower defence game and I am facing an issue in Phaser with tiled maps.
You see different layers in tiled always have coordinates from (0,0) to (600,600) -> or whatever your tiled width and height is. I have a backgroundLayer and a path. The creeps properly collide with the path.
Now I am trying to change the cursor to a building sprite (for UI when I click on some button and select a tower I want it to turn red when it is on the road or above another tower/creep) and I am using an overlap function for path and buildings.
This overlap function in Phaser checks the rectangle of building sprite and path, but path rectangle is the whole map. The collision works but I only need an overlap. Any ideas how to achieve this? Here is my code.
var RedPlanetGame = RedPlanetGame || {};
var pressed = {
is: false
};
var buildingOverlaps = {
is: false
};
//title screen
RedPlanetGame.Game = function () {
};
RedPlanetGame.Game.prototype = {
create: function create() {
//A door for multyplayer
this.players = [];
this.player = new Player(1, 'Daniel', 300);
this.players.push(this.player);
this.playerInfo = {};
//Tile map
this.map = this.game.add.tilemap('sample2');
this.map.addTilesetImage('32x32_map_tile v3.1 [MARGINLESS]', 'gameTiles');
//background and layers
this.backgroundlayer = this.map.createLayer('backgroundLayer');
this.path = this.map.createLayer('path');
this.map.setCollisionBetween(1, 2000, true, 'backgroundLayer');
this.map.setCollisionBetween(1, 2000, true, 'path');
//objects from tile map
this.spawnCreepsAt = this.map.objects['objectsLayer'][0];
this.destinationForCreeps = this.map.objects['objectsLayer'][1];
//resize world
this.backgroundlayer.resizeWorld();
//this.game.world.setBounds(0, 0, 100, 100);
//groups
this.game.enemies = new UnitsPoolFactory(this.game);
this.game.buildings = this.game.add.group();//TODO: make buildings for each player
this.game.bullets = new BulletsPoolFactory(this.game);
//creep spawning
var _this = this;
const creepYOffset = 15;
setInterval(function () {
_this.game.enemies.factory(_this.spawnCreepsAt.x, _this.spawnCreepsAt.y + creepYOffset, UNIT_TYPES.CREEP1);
}, 1000);
//text and player info
var textX = 150;
var textY = 0;
this.playerInfo.gold = this.game.add.text(textX, textY, 'Player gold: ' + this.player.gold,
{font: "24px Arial", fill: '#FFD700'}
);
//Here is test straight forward code for building towers
this.game.build = this.game.add.group();
this.buildingSprite = this.game.add.sprite(0, 0, 'tower1-1');
this.game.physics.enable(this.buildingSprite, Phaser.Physics.ARCADE);
this.buildingSprite.anchor.setTo(0.5);
this.buildingSprite.scale.setTo(0.5);
this.game.build.add(this.buildingSprite);
console.log(this.path.getBounds());
console.log(this.backgroundlayer.getBounds());
},
update: function update() {
var _this = this;
//Camera follow cursor
if (this.game.input.mousePointer.x > gameHeight - gameHeight / 10) {
this.game.camera.x += 10;
} else if (this.game.input.mousePointer.x <= 100) {
this.game.camera.x -= 10;
}
if (this.game.input.mousePointer.y > gameWidth - gameWidth / 10) {
this.game.camera.y += 10;
} else if (this.game.input.mousePointer.y <= 100) {
this.game.camera.y -= 10;
}
//check for collision between enemy and non-path layer
this.game.physics.arcade.collide(this.game.enemies, this.backgroundlayer);
//checks for collision between bullets and enemies
this.game.physics.arcade.overlap(this.game.bullets, this.game.enemies, function (bullet, enemy) {
enemy.takeHit(bullet, _this.player);
bullet.kill();
}, null, this);
//updates enemies
this.game.enemies.forEach(function (enemy) {
enemy.onUpdate(_this.destinationForCreeps);
});
//updates buildings
this.game.buildings.forEach(function (building) {
building.onUpdate(_this.game.bullets);
});
//on mouse down event
if (this.game.input.activePointer.leftButton.isDown && !pressed.is) {//yo Yoda
//builds new building of type TOWER1
buffer(pressed, 1000);
if (Building.prototype.canBuild(this.player.gold, Tower1.prototype.moneyCost)) {
var poss = this.game.input.mousePointer;
BuildingsFactory(this.game, poss.x, poss.y, this.player, BUILDING_TYPES.TOWER1);
this.player.gold -= Tower1.prototype.moneyCost
} else {
alert('Not enought gold');
}
}
//Here is test straight forward code for building towers
if (Phaser.Rectangle.contains(this.buildingSprite.body, this.game.input.x, this.game.input.y)) {
this.buildingSprite.body.velocity.setTo(0, 0);
}
else {
this.game.physics.arcade.moveToPointer(this.buildingSprite, 700);
}
this.game.physics.arcade.collideGroupVsTilemapLayer(this.game.build, this.path, function (sprite) {
if (!buildingOverlaps.is) {
buffer(buildingOverlaps, 500);
console.log('overlap')
}
}, null, this, true);
},
render: function render() {
this.playerInfo.gold.text = 'Player gold: ' + this.player.gold;
}
};

Categories

Resources