Working from this I have the following code:
export default {
data(){
return {
width: 0,
height: 0,
}
},
methods: {
resizedWindow: _.throttle(this.reset, 200),
reset(){
this.width = window.innerWidth;
this.height = window.innerHeight;
}
},
mounted(){
this.reset();
window.addEventListener('resize', this.resizedWindow);
}
}
But this gives me the following error:
Uncaught TypeError: Cannot read property 'reset' of undefined
Usually this is to do with this and I (usually) know how to fix that. You do something like this:
// Replace previous resizeWindow with...
resizedWindow(){
let vm = this;
_.throttle(vm.reset, 200);
},
But this never fires the reset method. I know it must be something silly or gap in my understanding of this – how can I make this work?
It seems that in your case this is referring to the window object. You can move your resizedWindow method definition to the created hook as seen here to have access to this as the Vue instance ..
export default {
data(){
return {
width: 0,
height: 0,
}
},
methods: {
reset(){
this.width = window.innerWidth;
this.height = window.innerHeight;
}
},
created() {
this.resizedWindow = _.throttle(this.reset, 200)
},
mounted(){
this.reset();
window.addEventListener('resize', this.resizedWindow);
}
}
Alternatively, you can make use of an IIFE ..
export default {
data(){
return {
width: 0,
height: 0,
}
},
methods: {
resizedWindow() { (_.throttle(this.reset, 200))() },
reset(){
this.width = window.innerWidth;
this.height = window.innerHeight;
}
},
mounted(){
this.reset();
window.addEventListener('resize', this.resizedWindow);
}
}
Related
So I've been trying to replicate the tile chebyshev lab outside of the phaser lab area, in glitch, and I've been Using the variable solution I got in this answer about using Phaser.gamestate for my variable that need to be update in many locations
And my Console hits me with Cannot read properties of undefined (reading 'gameState')
I've tried the this context setting too, but it continues this error, what can I do to fix it?
My Code:
import Phaser from "../lib/phaser.js";
export default class Game extends Phaser.Scene {
constructor() {
super("game1");
}
preload() {
this.load.image(
"Tileset",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/pixil-frame-0%20(17).png?v=1675985219390"
);
this.load.tilemapTiledJSON(
"map",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/Map.tmj?v=1675985261369"
);
this.load.spritesheet(
"player",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/pixil-frame-0%20(13).png?v=1675904194091",
{ frameWidth: 32, frameHeight: 32 }
);
}
create() {
this.gameState = {
map: "",
cursors: "",
};
this.gameState.map = this.make.tilemap({ key: "map" });
this.tiles = this.gameState.map.addTilesetImage("tileSet", "Tileset");
this.worldLayer = this.gameState.map.createLayer(
"Block Layer",
this.tiles,
0,
0
);
this.player = this.physics.add.sprite(0, 0, "player", 1);
this.cameras.main.setBounds(
0,
0,
this.gameState.map.widthInPixels,
this.gameState.map.heightInPixels
);
this.cameras.main.startFollow(this.player);
this.gameState.cursors = this.input.keyboard.createCursorKeys();
}
update() {
function updateMap() {
console.log(this.gameState)
var origin = this.gameState.map.getTileAtWorldXY(
this.player.x,
this.player.y
);
this.gameState.map.forEachTile(function (tile) {
var dist = Phaser.Math.Distance.Chebyshev(
origin.x,
origin.y,
tile.x,
tile.y
);
tile.setAlpha(1 - 0.1 * dist);
}, this);
}
if (this.gameState.cursors.left.isDown) {
this.player.setVelocityX(-50);
this.player.anims.play("left", true);
} else if (this.gameState.cursors.right.isDown) {
this.player.setVelocityX(50);
this.player.anims.play("right", true);
} else if (this.gameState.cursors.up.isDown) {
this.player.setVelocityY(-50);
} else if (this.gameState.cursors.down.isDown) {
this.player.setVelocityY(-50);
} else {
this.player.setVelocityX(0);
}
updateMap();
}
}
Update
I've put the function outside the scene, no change whatsoever
new code
import Phaser from "../lib/phaser.js";
export default class Game extends Phaser.Scene {
constructor() {
super("game1");
}
preload() {
this.load.image(
"Tileset",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/pixil-frame-0%20(17).png?v=1675985219390"
);
this.load.tilemapTiledJSON(
"map",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/Map.tmj?v=1675985261369"
);
this.load.spritesheet(
"player",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/pixil-frame-0%20(13).png?v=1675904194091",
{ frameWidth: 32, frameHeight: 32 }
);
}
create() {
this.gameState = {
map: "",
cursors: "",
};
this.gameState.map = this.make.tilemap({ key: "map" });
this.tiles = this.gameState.map.addTilesetImage("tileSet", "Tileset");
this.worldLayer = this.gameState.map.createLayer(
"Block Layer",
this.tiles,
0,
0
);
this.player = this.physics.add.sprite(0, 0, "player", 1);
this.cameras.main.setBounds(
0,
0,
this.gameState.map.widthInPixels,
this.gameState.map.heightInPixels
);
this.cameras.main.startFollow(this.player);
this.gameState.cursors = this.input.keyboard.createCursorKeys();
}
update() {
if (this.gameState.cursors.left.isDown) {
this.player.setVelocityX(-50);
this.player.anims.play("left", true);
} else if (this.gameState.cursors.right.isDown) {
this.player.setVelocityX(50);
this.player.anims.play("right", true);
} else if (this.gameState.cursors.up.isDown) {
this.player.setVelocityY(-50);
} else if (this.gameState.cursors.down.isDown) {
this.player.setVelocityY(-50);
} else {
this.player.setVelocityX(0);
}
updateMap();
}
}
function updateMap() {
console.log(this.gameState);
var origin = this.gameState.map.getTileAtWorldXY(
this.player.x,
this.player.y
);
this.gameState.map.forEachTile(function (tile) {
var dist = Phaser.Math.Distance.Chebyshev(
origin.x,
origin.y,
tile.x,
tile.y
);
tile.setAlpha(1 - 0.1 * dist);
}, this);
}
I think the problem can be solved by moving the function updateMap out of the update function/method. Making updateMap a function/mehtod of the Game class.
Like this the this inside of the updateMap function should be pointing to the correct object.
Sample Code snippet (updated):
update() {
if (this.gameState.cursors.left.isDown) {
...
}
...
// call the method
this.updateMap();
}
// the function is now a method of the class
updateMap() {
console.log(this.gameState)
var origin = this.gameState.map.getTileAtWorldXY(
this.player.x,
this.player.y
);
...
}
...
i'm learning vue and i have small problem.
I've created code, which receive some informations from webserwer (via socket) and this code works fine.
But i would like to do very simple thing - display info as variable in HTML and i have problem with it.
My code is:
export default {
components: {
BCard,
BButton,
},
data() {
return {
connection: null,
json: {
cmd: 'start',
width: 1024,
height: 800,
url: 'https://www.google.com',
token: '',
service_id: 1,
thumbnail_width: 100,
thumbnail_height: 100,
},
}
},
created() {
console.log('Starting Connection to WebSocket')
this.connection = new WebSocket('ws://127.0.0.1:8080/')
// this.connection = new WebSocket('ws://echo.websocket.org')
this.connection.onopen = function (event) {
console.log(event)
console.log('Success')
}
this.connection.onmessage = webSocketOnMSG
},
methods: {
sendMessage(message) {
console.log(this.connection)
console.log(message)
console.log(JSON.stringify(message))
const dat = this.connection.send(JSON.stringify(message))
console.log('TT', dat)
},
drawItem() {
const img = document.createElement('img')
const canvas = document.getElementById('canvasId')
img.src = 'http://image...'
img.onload = function (a) {
const h = a.target.height
const w = a.target.width
const c = canvas.getContext('2d')
canvas.width = w
canvas.height = h
c.drawImage(img, 0, 0)
document.getElementById('draw-image-test').appendChild(canvas)
}
},
webSocketOnMSG(msg) {
console.log(msg)
},
},
}
and i would like to add code like this:
data: {
xposition: 'xpos',
yposition: 'ypos'
}
but when i'm adding it to created earlier data() i have error, so this doesn't work:
data() {
xposition: 'xpos',
yposition: 'ypos',
return {...}
}
where should i add code to replace variables {{xposition}} and {{yposition}} in HMTL?
You must put your new variables inside your returned object in the data function, alongside your 'json' variable. You need to declare them first as empty values, and then add the proper values in your API call callback
data() {
return {
xposition: '',
yposition: '',
...
}
}
webSocketOnMSG(msg) {
// this will change your component's xposition property
this.xposition = msg.propertyYouWantToAccess
},
<template>
<form #submit.prevent="uploadMeasurement(measure)">
<input v-model="measure.length">
<input v-model="measure.width">
</form>
</template>
<script>
export default {
data() {
return {
measure: this.createFreshMeasure(),
};
},
computed: {
sqftTotal: function() {
return this.length * this.width;
}
},
methods: {
uploadMeasurement(measure) {
MeasurementService.uploadMeasurement(measure)
.then(...);
this.measure = this.createFreshMeasure();
})
.catch(error => {
this.error = error.response.data.error;
});
},
createFreshMeasure() {
return {
length: this.length,
width: this.width,
sqftTotal: this.sqftTotal
};
}
</script>
On submit, I'd like to calculate a square footage value using the values placed into the length and width inputs and send all three into the Mongo database.
The database is storing a value for sqftTotal when I send a hard-coded value directly over Postman, so it's capable of doing it, but this Vue form isn't accomplishing that task.
methods: {
uploadMeasurement() {
let measure = this.measure;
measure.sqftTotal = this.sqftTotal;
MeasurementService.uploadMeasurement(measure)
...
Got it, thanks to everyone for your input. Had to remove the argument from the method and declare it before the service call.
The easiest way to accomplish this would be something like this.. I have commented different options within the code to help explain things..
new Vue({
el: "#root",
template: `
<div>
<form ref="form">
<!--<input v-model="measure.length">
<input v-model="measure.width">-->
<input v-model="length">
<input v-model="width">
</form>
<button #click.prevent="uploadMeasurement">Submit</button>
</div>
`,
data: {
//measure: ""
length: "",
width: "",
},
computed: {
sqftTotal: function() {
//return this.measure.length * this.measure.width;
return this.length * this.width;
}
},
methods: {
uploadMeasurement() {
/** This is where you would POST the data **/
// You can either submit the form:
// -NOTE: '...$refs.form...' below must match the ref
// you assign to the <form ref="form"> element.
// this.$refs.form.$el.submit();
// ~ OR ~
// manually POST via fetch, etc:
// fetch('/url/to/post/to', {
// method: 'POST',
// body: JSON.stringify({
// length: this.measure.length,
// width: this.measure.width,
// sqftTotal: this.sqftTotal
// })
// })
alert(JSON.stringify({
//length: this.measure.length,
//width: this.measure.width,
length: this.length,
width: this.width,
sqftTotal: this.sqftTotal
}));
},
createFreshMeasure() {
this.length = 10;
this.width = 5;
//return {
// length: 10,
// width: 5
//};
}
},
created() {
this.createFreshMeasure();
//this.measure = this.createFreshMeasure();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<div id="root"></div>
I recommend cleaning up your code like below, as Vue often has issues when using object properties as a model like that
<template>
<form #submit.prevent="uploadMeasurement()">
<input v-model="length">
<input v-model="width">
</form>
</template>
<script>
export default {
data() {
return {
length: null,
width: null,
};
},
computed: {
sqftTotal: function() {
return this.length * this.width;
}
},
methods: {
uploadMeasurement() {
MeasurementService.uploadMeasurement({
length: this.length,
width: this.width,
sqftTotal: this.sqftTotal
})
.then(() => {
console.log('save success!');
})
.catch(error => {
this.error = error.response.data.error;
});
},
}
</script>
Is there any difference in behavior between, say, sprite.setVelocity(100,100) and sprite.body.setVelocity(100,100)? (Assuming the sprite has been added to this.physics.)
Bonus question: what is exactly referenced by this in the global Phaser scope? Is there any difference if I assign something to this.physics in the global scope, and if I assign it inside an ES5 Phaser class, like a scene?
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600, loader: {
baseURL: 'https://raw.githubusercontent.com/nazimboudeffa/assets/master/',
crossOrigin: 'anonymous'
},
scene: {
preload: preload,
create: create,
update: update
},
physics: {
default: 'arcade'
}
};
var game = new Phaser.Game(config);
var cursors, sprite, player;
function preload ()
{
this.load.image('alien', 'sprites/phaser-alien.png');
this.load.image('alien2', 'sprites/alien2.png');
}
function create ()
{
player = this.physics.add.sprite(50, 50, 'alien');
player.setCollideWorldBounds(true);
sprite = this.add.sprite(150, 50, 'alien2');
cursors = this.input.keyboard.createCursorKeys();
}
function update ()
{
if (cursors.left.isDown)
{
//player.setVelocityX(-160);
sprite.body.setVelocityX(-160);
}
else if (cursors.right.isDown)
{
player.setVelocityX(160);
//sprite.setVelocityX(160);
}
else if (cursors.down.isDown)
{
player.setVelocityY(160);
//sprite.setVelocityY(160);
}
else if (cursors.up.isDown)
{
player.setVelocityY(-160);
//sprite.setVelocityY(-160);
}
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.18.1/dist/phaser.min.js"></script>
I have a Paper instance with a tool that just draws a path on mouseMove and deletes the segments at the start of that path if the number of segments is greater than 50. Everything works perfect this far. this is the code:
<template>
<div>
<canvas id="canvas" resize></canvas>
</div>
</template>
<script>
import paper from 'paper';
export default {
name: 'home',
components: {
},
created() {
paper.install(window);
},
mounted() {
const canvas = this.$el.querySelector('#canvas');
paper.setup(canvas);
const path = new Path();
path.strokeColor = '#f5bb56';
path.strokeWidth = 2;
this.tool = new Tool()
this.tool.onMouseMove = event => {
if (path.segments.length > 50) {
path.removeSegment(0)
};
path.add(event.point);
path.smooth({
type: 'continuous'
});
};
view.draw()
},
};
</script>
<style lang="scss">
#canvas {
width: 100%;
height: 100%;
}
</style>
The problem is that now i want to start deleting segments from that path with an interval of 50 miliseconds but stop executing that when a new segment is added. I'm looking for something to set a variable into a timeout(() => {eraseFunction()}), when the event is not fired for about two seconds.
i added a clearTimeout pointing to the variable that contains it at the start of the mouseMove event and setting it at the end, so if there's a timeout running, i remove it when the mouseMove starts:
export default {
name: 'home',
components: {
},
data() {
return {
tool: null,
path: null,
erase: null,
}
},
created() {
paper.install(window);
},
mounted() {
const canvas = this.$el.querySelector('#canvas');
paper.setup(canvas);
this.path = new Path();
this.path.strokeColor = '#f5bb56';
this.path.strokeWidth = 2;
this.tool = new Tool()
this.tool.onMouseMove = event => {
clearTimeout(this.erase);
if (this.path.segments.length > 50) {
this.path.removeSegment(0)
};
this.path.add(event.point);
this.path.smooth({
type: 'continuous'
});
this.erase = setTimeout(() => {
this.eraseFunction()
}, 2000);
};
view.draw()
},
methods: {
eraseFunction() {
setInterval(() => {
this.path.removeSegment(0);
}, 500);
}
}
};
</script>
the problem is that the timeout is not removed and given a certain amount of time, i can´t draw new segments because they´re deleted inmediately.
You need to clear setInterval also. You are only clearing setTimeout. setInterval is still running an deleting your segments.
ClearInterval need the intervalID you want to clear. The intervalID is given by setInterval call.
You should return the result of setTimout call in eraseFunction:
eraseFunction() {
return setInterval(() => {
this.path.removeSegment(0);
}, 500);
}
And you should assign to this.erase the result of eraseFunction call, instead of the setTimeout:
setTimeout(() => {
this.erase = this.eraseFunction()
}, 2000);