I am a new web dev and is currently working with Vue.js framework.
Decided to try out making a game with Phaser 2, and I am currently loving it!
Although i ran in to some problems with mouse events, i have no problems with key down events ;)
currently I am trying to click on an image, just to console log it out. (will want to drag later on.)
but first thing is first, I cant even get my console log out.
here is my code, and I am using it with vue.js!
Any help will be great ! Thank you!
Below are some snippets of my code that i think will be important
mounted () {
let self = this
if (this.game == null) {
this.game = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, this.$el, {
preload: function preload () {
self.preload(this)
},
create: function create () {
self.create(this)
},
update: function update () {
self.update(this)
},
render: function redner () {
self.render(this)
}
})
}
}
preload () {
this.game.load.image('pink', require(`#/assets/images/packing/pink-bg.png`))
this.game.load.image('cat', require(`#/assets/images/packing/cat-head.png`))
this.game.load.image('table', require(`#/assets/images/packing/table.png`))
this.game.load.image('plate', require(`#/assets/images/packing/plate.png`))
this.game.load.spritesheet('container', require(`#/assets/images/packing/container-set.png`), 310, 270)
this.game.load.spritesheet('scorePlate', require(`#/assets/images/packing/kueh-set.png`), 313, 270)
}
let cat = this.game.add.sprite(0, 0, 'cat')
cat.height = this.game.world.height * 0.25
cat.width = this.game.world.width * 0.15
let table = this.game.add.sprite(0, 0, 'table')
table.height = this.game.height
table.width = this.game.width
this.game.physics.startSystem(Phaser.Physics.ARCADE)
let containerBullu = this.game.add.sprite(this.game.world.width - (this.game.world.centerX + this.game.world.centerX), this.game.world.height / 7, 'container')
containerBullu.height = this.game.world.height * 0.55
containerBullu.width = this.game.world.width * 0.35
containerBullu.frame = 4
containerBullu.inputEnabled = true
containerBullu.events.onInputDown.add(this.listener, containerBullu)
let containerCornflake = this.game.add.sprite(this.game.world.width - (this.game.world.centerX + this.game.world.centerX / 1.8), -50, 'container')
containerCornflake.height = this.game.world.height * 0.6
containerCornflake.width = this.game.world.width * 0.35
containerCornflake.frame = 9
render (phaser) {
this.game.debug.spriteInfo(this.containerBullu, 100, 100)
}
listener (containerBullu) {
console.log(containerBullu)
},
destroyed () {
this.game.destroy()
}
I hope to hear from anyone soon!
Thanks!
sincerely,
desperate and crying new front end web developer. (I was on it for 4hours. as of now. still going... )
Related
The game I'm creating doesn't require any physics, however you are able to interact when hovering over/clicking on the sprite by using sprite.setInteractive({cursor: "pointer"});, sprite.on('pointermove', function(activePointer) {...}); and similar.
I ran into some issues with the interactive area and wanted to debug it by showing the "area" that is interactable. However I could only find ways to do that that are related to Arcade Physics. Is there any way to get something like a debug outline around my interactable area without Physics?
Out-Of-The-Box, without physics, I don't know any way, but one could get this function/feature with a small helper-function. (but maybe there is something, since phaser is a really extensive framework. But I also couldn't find anything).
Something like this, could do the trick, and is reuseable:
function debugSpriteArea(scene, sprite){
let debugRect = scene.add.rectangle(
sprite.x, sprite.y,
sprite.displayWidth, sprite.displayHeight,
0xff0000).setOrigin(sprite.originX,
sprite.originY);
debugRect.setDepth(-1);
}
Here the help-function in action:
let Scene = {
preload ()
{
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
},
create ()
{
// Animation set
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('brawler', { frames: [ 0, 1, 2, 3 ] }),
frameRate: 8,
repeat: -1
});
const cody = this.add.sprite(200, 100, 'brawler')
.setOrigin(0.5);
debugSpriteArea(this, cody);
cody.play('walk');
cody.setInteractive();
this.mytext = this.add.text(10, 10, 'No Hit', { fontFamily: 'Arial' });
cody.on('pointerdown', function (pointer) {
let originXOffset = cody.displayWidth * cody.originX;
let originYOffset = cody.displayHeight * cody.originY;
let x = (pointer.x - cody.x + originXOffset ) / (cody.displayWidth / cody.width)
let y = (pointer.y - cody.y + originYOffset) / (cody.displayHeight / cody.height);
if(cody.anims && cody.anims.currentFrame){
let currentFrame = cody.anims.currentFrame;
let pixelColor = this.textures.getPixel(x, y, currentFrame.textureKey, currentFrame.textureFrame);
if(pixelColor.a > 0) {
this.mytext.text = 'hit';
} else {
this.mytext.text = 'No hit';
}
}
}, this);
}
};
function debugSpriteArea(scene, sprite){
let debugRect = scene.add.rectangle(
sprite.x, sprite.y,
sprite.displayWidth, sprite.displayHeight,
0xff0000).setOrigin(sprite.originX,
sprite.originY);
debugRect.setDepth(-1);
}
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: Scene
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I am new to Phaser Framework and I wanted to try making some prototype of 2D pool game from top down perspective. The problem that I have right now is detecting if all balls have stopped moving before restarting.
I use Physics.Matter and here is the source code when create so far:
this.matter.world.setBounds(0, 0, 720, 1280, 32, false, false, false, true);
this.add.image(400, 300, 'sky');
var ball = this.matter.add.image(360, 1000, 'ball');
ball.setCircle();
ball.setVelocity(-5, -20);
ball.setBounce(0.5);
for (var i = 1; i < 10; i++) {
var target = this.matter.add.image(Phaser.Math.Between(400,450), Phaser.Math.Between(400,450), 'target');
target.setCircle();
target.setVelocity(0, 0);
target.setBounce(0.7);
target.setFriction(0, 0.01);
target.setSleepEvents(true, true);
}
this.matter.world.on('sleepstart', function() {console.log('sleepstart');});
this.matter.world.on('sleepend', function() {console.log('sleepend');});
This would detect if each target has slept but I need to detect if ALL of them stopped moving. I cannot count how many has slept because sometimes when a target has entered sleep state, there is a chance some other body will bounce off it and woke it up again.
Is there any way to globally detect them?
EDIT: As a fallback plan I add a basic JS function to be called whenever update is called and count the sleeping bodies, which looks like it should not be a proper way:
var isActive = false;
// Some commands here that changes isActive = true
function onupdate() {
if (isActive) {
var bodyCount = this.matter.world.getAllBodies().filter(o => o.isSleeping === true).length;
console.log(bodyCount);
if (bodyCount >= 11) {
isActive = false;
}
}
}
I would put all objects you want to track into a phaser group (https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Group.html) and iterate over the items in the group, to see if all have the property isSleeping set to true;
Warning: I can't say how performant this solution is, youre use case. If it is too slow, I would setup a counter variable, and count it down / up on sleepstart and sleepend. And when the counter is 0 all are sleeping.
Here a working demo, how I would do it:
(explaination are in the code, as comments)
// fix to prevent 'Warnings' in stackoverflow console
console.warn = _ => _
var config = {
type: Phaser.AUTO,
width: 400,
height: 100,
scene: { create },
physics: {
default: 'matter',
matter: {
debug: true,
setBounds: {
x: 0,
y: 0,
width: 400,
height: 100
},
enableSleeping: true
}
}
};
function create(){
// create the Phaser Group
this.targets = this.add.group();
for (var i = 1; i < 10; i++) {
var target = this.matter.add.image(200, 0, 10, 10, 'target');
target.setCircle();
target.setBounce(0.7);
target.setFriction(0, 0.01);
target.setSleepEvents(true, true);
// Add Item to the Group
this.targets.add(target);
}
this.matter.world.on('sleepstart', function(event, item){
// Check all targets are sleeping
if(!this.targets.getChildren().some( target => !target.body.isSleeping)){
console.log('all are sleeping');
}
}, this); // <- pass the scene as context
this.matter.world.on('sleepend', function() {console.log('sleepend');});
}
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I have been digging into the documentation, tutorials, stackoverflow questions literally all day and cannot find the solution to this problem. Please please take pity on me and help me!
I have a watering can that I put an event listener on, but on mousedown, objects near and to the left get selected ie. the tree trunk or a leaf (code not included) and then I am able to drag and drop that object around until I put it down and it is out of range of the watering can. If I drop it near the watering can, it will get selected again when I click. This is NOT the intended behavior, I want the actual watering can I clicked to be selected and then proceed to get dragged and dropped etc. There is kind of a lot of code here but I am not sure where the problem lies anymore so I am including almost all of it. It's like the watering can thinks it is elsewhere or the ray thinks it is shooting elsewhere. PLEASE TELL ME IF I CAN CLARIFY ANYTHING OR SEND MORE CODE. I just started learning three.js yesterday so there are definitely things I don't understand but I am pretty clear on what is supposed to be happening here... and this is not it :D
const WateringCan = function() {
this.mesh = new THREE.Object3D();
const mat = new THREE.MeshStandardMaterial({ metalness: 0.8, color: 0xadb2bd });
// Create the can
const geomCan = new THREE.CylinderGeometry(15, 15, 25, 10, 10);
geomCan.applyMatrix( new THREE.Matrix4().makeScale(1.1, 1.0, 0.6));
geomCan.computeBoundingBox();
geomCan.computeFaceNormals();
const can = new THREE.Mesh(geomCan, mat);
can.castShadow = true;
can.receiveShadow = true;
this.mesh.add(can);
// Create the handle
const geomHandle = new THREE.TorusGeometry( 10, 2, 8, 6, Math.PI);
geomHandle.applyMatrix( new THREE.Matrix4().makeScale(0.9, 1.1, 1.0));
const handle = new THREE.Mesh(geomHandle, mat);
handle.rotation.z = 4.5;
handle.position.x = 13.5;
handle.castShadow = true;
handle.receiveShadow = true;
this.mesh.add(handle);
// Create spout
const geomSpout = new THREE.CylinderGeometry(1, 3, 20, 5, 5);
const spout = new THREE.Mesh(geomSpout, mat);
spout.rotation.z = 1;
spout.position.x = -22;
spout.position.y = 10;
spout.position.z = 3;
spout.castShadow = true;
spout.receiveShadow = true;
this.mesh.add(spout);
const domEvents = new THREEx.DomEvents(camera, renderer.domElement);
domEvents.addEventListener(can, 'mousedown', (e) => onWateringCanMouseDown(e));
};
let wateringCan;
function createWateringCan() {
wateringCan = new WateringCan();
wateringCan.name = "wateringCan";
wateringCan.mesh.position.x = 120;
wateringCan.mesh.position.y = -30;
wateringCan.mesh.position.z = -10;
scene.add(wateringCan.mesh);
objects.push(wateringCan.mesh);
}
let plane;
function createPlane() {
plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(WIDTH, HEIGHT, 8, 8), new THREE.MeshBasicMaterial({ color: 0xffffff, alphaTest: 0, visible: false }));
scene.add(plane);
}
let selection;
function onWateringCanMouseDown(e) {
const mouseX = (e.clientX / WIDTH) * 2 - 1;
const mouseY = -(e.clientY / HEIGHT) * 2 + 1;
const mouse3D = new THREE.Vector3(mouseX, mouseY, 0.5);
mouse3D.unproject(camera);
raycaster.set(camera.position, mouse3D.sub(camera.position).normalize());
const intersectedObjects = raycaster.intersectObjects(objects, true);
if (intersectedObjects.length > 0) {
selection = intersectedObjects[0].object;
const intersectPlane = raycaster.intersectObject(plane);
offset.z = selection.position.z;
offset.copy(intersectPlane[0].point).sub(plane.position);
}
}
function onDocumentMouseMove(e) {
const mouseX = (e.clientX / WIDTH) * 2 - 1;
const mouseY = -(e.clientY / HEIGHT) * 2 + 1;
const mouse3D = new THREE.Vector3(mouseX, mouseY, 0.5);
mouse3D.unproject(camera);
raycaster.set(camera.position, mouse3D.sub(camera.position).normalize());
raycaster.setFromCamera( mouse3D.clone(), camera);
if (selection) {
offset.z = selection.position.z;
const intersectPlane = raycaster.intersectObject(plane);
selection.position.copy(intersectPlane[0].point.sub(offset));
} else {
const intersectedObjects = raycaster.intersectObjects(objects);
if (intersectedObjects.length > 0) {
plane.position.copy(intersectedObjects[0].object.position);
plane.lookAt(camera.position);
}
}
}
function onDocumentMouseUp(e) {
selection = null;
}
Things I have already tried: computeBoundingBox() on everything I have applyMatrix on, refactoring mouse3D/raycaster around in slightly different ways, moving the can far away (then nothing gets selected). I also had the event listener set on the document for a while and I did not have this problem, but the watering can pieces did not stick to each other, the individual spout/can/handle would get dragged and dropped. But at least it knew then that I was clicking on them! Also having the ability to drag and drop literally everything on the page was fun but also not the point, like I don't need all the leaves on my tree to move around.
Please please help me if you can!! I have been messing around with this all day and it is killing my soul. :D
Okay, so. I did not find out what the reason behind this strange behavior was so I decided to kind of restructure what I was doing and I am no longer having this problem.
What I did is:
removed the event listener from the watering can and put it back on the document
removed all objects but the watering can from my objects array that gets looked through on raycaster.intersectObjects so now nothing but that can be dragged and dropped
things are mostly fine now
I am making a pretty simple game demo as part of my senior project, in which I'm trying to make a basic matching game that can help teach some basic mathematical skills. I would like to have the player be able to flip over cards to check if they have the right answer, however, the variable I am using to track whether or not the mouse is being clicked doesn't seem to ever register as true.
var isMouseDown = false;
c.onmousedown =
function(evt) { isMouseDown = true; };
c.onmouseup =
function(evt) { isMouseDown = false; };
// Keep track of where the mouse is
var mouse = {x: 0, y: 0};
c.onmousemove =
function(evt) {
mouse.x = evt.clientX;
mouse.y = evt.clientY;
};
This is where I use the variable:
this.clicked = function() {
c.strokeRect(500, 500, 20, 20);
if (isMouseDown) {
c.strokeRect(400, 400, 20, 20);
var diffX = mouse.x - this.x;
var diffY = mouse.y - this.y;
if (0 <= diffX <= 40) {
var xInRange = true;
} else {
xInRange = false;
}
if (0<= diffY <= 60) {
var yInRange = true;
c.strokeRect(this.x + 10, this.y + 25, 20, 20);
} else {
yInRange = false;
}
if (xInRange && yInRange) {
this.flip();
}
}
};
I have thrown in a few instructions for the canvas to build a box to see if it is compiling that part of the code, and it looks like the first one is being drawn when I run the program, but the second one (the one in the if statement) isn't, so I figured that would be where I'm running into a problem.
EDIT: Here is where I call on the function (this isn't finished, so there's a few pieces of code lying around unused):
var cmTID;
var timeStep = 50; //milliseconds
var numCards = 10;
function update() {
var card = new Card(10, 10, 60, 40, 5);
card.draw();
card.clicked();//nothing after this compiles atm
c.strokeRect(200, 200, 30, 30);
clearTimeout(cmTID);
cmTID = setTimeout(update, timeStep);
}
I don't have a ton of experience in Javascript, though I have done a fair amount of work in Java for AP Computer Science, which I took my sophomore year. And if you are wondering, yes, I bit off a little more than I could chew here :P
Can anyone give me pointers on what might be going wrong here? Thanks!
It seems that you are trying to add mouse events to the context c. Instead add it to the actual canvas element.
I am having some difficulty copying a canvas from my buffer canvas to the canvas on my page. Thus far I have built a Render object, a Level object, and I have my main game loop (currently just a launch function).
I am able to write to the buffer canvas in the Render object just fine (if I add a document.body.append() statement the canvas successfully appends to the document with the necessary content) but I cannot copy from the buffer canvas to my main canvas. See below for a snippet of my code:
function Renderer(bufferWidth, bufferHeight) {
var c=document.createElement('canvas');
var ctx=c.getContext('2d');
c.width=bufferWidth;
c.height=bufferHeight;
this.getBufferContext = function() { return ctx; };
this.getBufferElement = function() { return c; };
this.drawToCanvas = function(canvasCtx) {
canvasCtx.drawImage(c,0,0);
};
}
var c = document.getElementById('mycanvas');
var ctx = c.getContext('2d');
var render = new Renderer(c.width, c.height);
var level1 = new Level('images/imagequality.png');
level1.Draw(render.getBufferContext());
render.drawToCanvas(ctx);
Note that Renderer is in a separate file and is loaded using the script tags in my HTML page.
As mentioned earlier, the drawToCanvas() function doesn't appear to successfully copy data from one canvas to another. Appending my source canvas confirms that it contains the expected data.
edit: I have listed my level code below.
function Level(mapname) {
var map=new Image();
map.src=mapname;
this.Draw = function(renderer) {
map.onload = function() { renderer.drawImage(map,0,0); };
};
}
I have good news, and I have bad news.
The good news is the code you show here works 100%
here is the demo: http://jsbin.com/upatij/edit#javascript,html,live
bad news: that means that something inside your Level code is broken as my stub Level code works perfectly in your framework... :-(
stub Level:
function Level() {
this.Draw = function(xxctx) {
for (var i = 0; i < 30; i++) {
xxctx.moveTo(10 + (i * 40 % 300), 10 + (parseInt(i / 6, 10) * 40));
xxctx.lineTo(40 + (i * 40 % 300), 40 + (parseInt(i / 6, 10) * 40));
xxctx.moveTo(40 + (i * 40 % 300), 10 + (parseInt(i / 6, 10) * 40));
xxctx.lineTo(10 + (i * 40 % 300), 40 + (parseInt(i / 6, 10) * 40));
}
xxctx.stroke();
};
}
good luck! -ck
AFTER YOUR SEEING YOUR LEVEL CODE:
The problem is one of synchronicity, your use of classes here are hiding the problem from you, via deceptive naming, as your Level.Draw, is not a draw function at all... let me unwrap it for you:
var c = document.getElementById('mycanvas');
var ctx = c.getContext('2d');
// var render = new Renderer(c.width, c.height);
var Renderer_c = document.createElement('canvas');
var Renderer_ctx = Renderer_c.getContext('2d');
document.body.appendChild(Renderer_c); //added to show
Renderer_c.width = c.width;
Renderer_c.height = c.height;
// var level1 = new Level('images/imagequality.png');
var map = new Image();
document.body.appendChild(map); //add to show
map.src = 'http://th06.deviantart.net/fs71/150/i/2011/255/9/5/omnom_upside_down_by_earnurm-d49pjnl.png';
console.log('at ' + 1);
// level1.Draw(render.getBufferContext());
map.onload = function() {
console.log('at ' + 3);
//this happens async:
alert('drawing now!');
Renderer_ctx.drawImage(map,0,0);
};
console.log('at ' + 2);
// render.drawToCanvas(ctx);
ctx.drawImage(Renderer_c, 0, 0);
If you run that code you will see that at the moment at which onload is called everything else has already executed, you'll notice how the console will read:
at 1
at 2
at 3
and as such, at the moment when alert('drawing now!'); is executed...
// render.drawToCanvas(ctx);
ctx.drawImage(Renderer_c, 0, 0);
will have already run... Basically your Draw() function is actually an asynchronous "Load". Unfortunately, you current conceptualization does not work. Your Draw() function needs to be an async one like this:
function Level(mapname) {
var map=new Image();
document.body.appendChild(map); //add to show
map.src=mapname;
this.asyncDraw = function(renderer, onComplete) {
map.onload = function() {
renderer.drawImage(map,0,0);
onComplete();
};
};
}
and the function should then be called like this in your example:
level1.asyncDraw(render.getBufferContext(), function() {
render.drawToCanvas(ctx);
});
I should probably go on to say that this type of asynchronisity makes HTML5 game programming a little tricky as you really have to throw up the "Loading..." spinner and refrain from going into your rendering loop until all "resources" have loaded. In all practicality you need the concept of "ready" eg. Load(fOnReady) AND Draw(ctx) instead of just asyncDraw(ctx, fOnReady)...
the updated jsbin is here: http://jsbin.com/upatij/2/edit
hope this helps -ck