player object undefined only in update()ƒ - javascript

not exactly sure what to call whats going on. I need to create a definition for the clients main player physics body and i can't read it or any of its properties, no matter where or how i call it, from update(). Also if this is a bit hard to understand Im a young and new JS programmer so bare with me. Im willing to change the construction of my scenes if i need to if anyone recommends something easier.
class MainScene extends Phaser.Scene {
constructor() {
super({ key: 'MainScene' })
}
preload() {
this.load.image('grass','./assets/map.png',);
this.load.spritesheet('graf', './assets/wang.png', { frameWidth: 200, frameHeight: 170})
}
create() {
this.add.image(100,400,'grass');
this.playerMap = {};
Client.askNewPlayer();
window.myScene = this;
this.body = this.matter.bodies.circle(
1,
1,
10,
{
isSensor: true
}
);
}
addNewPlayer(id, x, y) {
if(id == clientID){
this.playerMap[id] = this.matter.add.sprite(x, y, 'graf','', {'shape' : this.body['player-20-00']}).setScale(.5);
this.player = this.playerMap[id];
this.cameras.main.centerOn(this.player.x, this.player.y)
}
else{
this.playerMap[id] = this.add.sprite(x,y,'graf').setScale(.5);
}
}
removePlayer(id){
this.playerMap[id].destroy();
delete this.playerMap[id];
}
movePlayer(id, x, y) {
// var player = this.playerMap[id];
// var distance = Phaser.Math.Distance.Between(player.x,player.y,x,y);
// var duration = distance*10;
// var tween = this.add.tween(player);
// tween.to({x:x,y:y}, duration);
// tween.start();
}
update(){
//haven't been able to access any variables Ive called from here
this.cameras.main.centerOn(this.player.x, this.player.y)//causes error "can't read properties of undefined"
//replacing this.player.y or y with playerMap[a].x or y doesn't work either even though its accessible from everywhere else and === (equivalent)
}
}
here is the client object, I'm pretty sure this doesn't affect my problem
var Client = {};
var clientID;
Client.socket = io.connect();
Client.askNewPlayer = function(){
Client.socket.emit('newplayer');
}
Client.socket.on('newplayer',function(data){
window.myScene.addNewPlayer(data.id,data.x,data.y);
});
Client.socket.on('allplayers',function(data){
console.log(data);
for(var i = 0; i < data.length; i++){
window.myScene.addNewPlayer(data[i].id,data[i].x,data[i].y);
}
});
Client.socket.on('remove',function(id){
window.myScene.removePlayer(id);
});
Client.socket.on('move',function(data){
window.myScene.movePlayer(data.id,data.x,data.y);
});
Client.socket.on('id',function(id){
clientID = id;
})

The issue is, that the update function is called, before a player is added ( aka before the this.player is set).
Since the update function will fire more or less right after the create function, the property player of the scene is not set yet. So this.player is undefined, which is the cause for the the error.
The solution is to check, if the this.player property is set before accessing it, in the update function.
As soon as the this.player property is set, the other commands in the if - clause are called.
update(){
if(this.player){
this.cameras.main.centerOn(this.player.x, this.player.y);
// ...
}
}
or like this, it is a bit better to read (following the "Return Early Pattern" ):
update(){
if(!this.player){
return ;
}
this.cameras.main.centerOn(this.player.x, this.player.y);
// ...
}

Related

Javascript Object Composition with assign & Object.create

trying to wrap my head around javascript composition using assign. The property on my base object is unexpectedly being shared between instances. What am I doing wrong? I have...
Stat.js:
import assign from 'object-assign';
var Stat = assign({}, {
_value: undefined,
get: function() {
return this._value;
},
set: function(n) {
var max = this.getMax();
if(n > max) {
this._value = max;
} else {
this._value = n;
}
},
getMax: function() {
return 1;
}
});
module.exports = Stat;
HitPoints.js:
import assign from 'object-assign'
import Stat from './Stat.js';
var HitPoints = assign({}, Stat, {
getMax: function() {
return 100;
}
});
module.exports = HitPoints;
Unit.js:
import assign from 'object-assign';
import HitPoints from 'HitPoints.js';
var Unit = assign({}, {
hp: Object.create(HitPoints)
}
);
module.exports = Unit;
Usage:
import Unit from 'Unit.js';
var u1 = Object.create(Unit);
console.log( u1.hp.get() ); // undefined - ok
u1.hp.set(11);
console.log( u1.hp.get() ); // 11 - ok
var u2 = Object.create(Unit);
console.log( u2.hp.get() ); // 11 - ???
u2.hp.set(22);
console.log( u1.hp.get() ); // 22 - ???
console.log( u2.hp.get() ); // 22
Thanks for your help...
For starters, a quick example of why people don't want you using class.
I don't necessarily hate class, but 90% of the reason to use class is to get inheritance, and while it's occasionally helpful, it can frequently be very painful.
class Person { }
class ArmedPerson extends Person {
constructor (details) {
super(details);
const gun = new Gun();
this.equipment = { gun };
}
attack (target) {
this.equipment.gun.fireAt(target);
}
}
class Civilian extends Person { }
class ArmedCivilian extends ArmedPerson {
/* ... shouldn't it be extending Civilian?
Maybe all Civilians should be armed?
Is this why most games take place in the US?
*/
}
class Soldier extends ArmedPerson {
constructor (personDetails) {
super(personDetails);
}
}
class UnarmedSoldier extends Soldier {
/* HOW DO I TAKE HIS GUN AWAY? */
constructor (personDetails) {
super(personDetails);
}
attack () {
/* I know he has a gun, and anybody hacking the game can use it, but what do I do here? */
}
}
class inheritance has shown itself to be one of those things that people have misused terribly, for the past 30+ years (just like every other useful tool out there).
Rather than inheritance, we can look at composition (via Dependency Inversion).
class Soldier {
constructor (personDetails, gun) {
/*...setup...*/
this.equipment = { gun };
this.selectedWeapon = gun;
}
attack (target) {
this.selectedWeapon.fireAt(target);
}
}
const soldier = new Soldier({ /*...details... */ }, new Gun());
Not a lot has changed, in terms of the end-result we wanted... we've been able to simplify really a lot, and now we can even give him a method to swap guns if we want, all because rather than bolting the gun into something that he inherits from, we're handing him a gun when we first meet him.
It could be any type of gun we want, as long as it can still be fired in a similar fashion.
The question arises:
are there better ways of making things reusable, then, if inheritance is completely off the table?
To that I say: inheritance shouldn't be completely off the table... ...it should just be so far off to the side that it should be an "aha" moment, when you discover that it really is the best and cleanest way to accomplish something (rather than attempting to inherit from .......something, anything, right now!).
Various languages have a concept referred to as Traits or Mix-Ins.
In something like Java, a close-ish approximation is Interfaces.
I'm not a huge fan of Interfaces (the structure, not the concept - love the concept).
In Java, Interfaces make you do more work, because they have you define the function, what the function takes, what it returns...
...but you can't give it any default behaviour (traditionally), so if you have 14 objects which implement the same interface, that's the same method you write out 14 times (plus the signature for the interface). Sometimes, those methods are going to be completely different in the specifics of the implementation; that's fine... ...sometimes, they'll be the exact same as what you intended when you wrote the interface to begin with.
That's less okay. Queue Traits; these are things which you define the interface of, define the behaviour for, and then copy onto your object.
In JS, we can even have some closure safety around them, by injecting context that they get to work from, rather than letting them assume they get to mess around with the entirety of this.
const Movable = (pos) => ({
up (distance) { pos.y += distance; },
down (distance) { pos.y -= distance; },
left (distance) { pos.x -= distance; },
right (distance) { pos.x += distance; }
});
class Point {
constructor (x, y) {
Object.assign(this, { x, y });
}
}
class Person {
constructor (position) {
Object.assign(this, { position }, Movable(position));
}
}
const person = new Person( new Point(0, 0) );
person.up( 20 );
person.position.y; // 20
If you'll note, Movable is returning a new instance of an object, with methods which change values on position. That object is having its methods copied onto the instance of person.
I can now create as many of these Traits as I'd like, and copy them onto as many objects as I'd like, and get reuse that way.
Well, this worked...
Stat.js:
var Stat = {
get: function() {
return this._value;
},
set: function(n) {
var max = this.getMax();
if(n > max) {
this._value = max;
} else {
this._value = n;
}
},
getMax: function() {
return 1;
}
}
HitPoints.js:
var HitPoints = function() {
return assign(Object.create(Stat), {
getMax: function() {
return 100;
}
});
}
Unit.js:
var Unit = function() {
return assign({},
Object.create(XYPiece),
Object.create(TeamMember),
{
hp: HitPoints()
}
);
}
Usage:
var u1 = Unit();
console.log( u1.hp.get() ); // undefined
u1.hp.set(11);
console.log( u1.hp.get() ); // 11
var u2 = Unit();
console.log( u2.hp.get() ); // undefined
u2.hp.set(22);
console.log( u1.hp.get() ); // 11
console.log( u2.hp.get() ); // 22
This article helped. Hooray!!!
Still, tho, if this is fundamentally an idiotic way to go about it, tell me...

How to declare instance of a class within a instance of class?

I am making a simple hmtl/js game. I'd like to have all the data of the Game in DataofGame. It is like tennis, it is simpler than tennis: there is only set and match. changeinSet is called on click.
But I think i have a problem with private variable so it doesn't work.
Uncaught TypeError: Cannot read property 'WordsoftheGame' of undefined
//Added
document.getElementById('playboutton').addEventListener('click', newGame);
function newGame() {
var DataofGame = new newGameData();
}
// New game
function newGameData() {
this.pointTeam1 = 0;
this.pointTeam2 = 0;
this.WordsoftheGame = ShuffleListe();
this.ASet = new aSet();
}
//How the set is manage ********************
function aSet() {
var oneWord = DataofGame.ListeMot;
// display the word and delete it from the list
document.getElementById('jouer').innerHTML = oneWord[0];
DataofGame.WordsoftheGame.shift();
this.turn = true;
this.score = 0;
}
function changeinSet() {
DataofGame.ASet.score += 1;
//This is the other team's turn:
DataofGame.ASet.turn = !DataofGame.ASet.turn;
};
//shuffle liste
ListOfWords = ['Artiste', 'Appeler', 'Cheval', 'Choisir', 'Ciel', 'Croire', 'Dormir'];
function ShuffleListe() {
data = shuffle(ListOfWords);
return data;
}
function newGameData(){
this.pointTeam1=0;
this.pointTeam2=0;
this.WordsoftheGame= ShuffleListe();
this.ASet=new aSet();
}
//How the set is manage ********************
function aSet(){
var oneWord=DataofGame.ListeMot;
// display the word and delete it from the list
document.getElementById('jouer').innerHTML=oneWord[0];
DataofGame.WordsoftheGame.shift(); // << DataofGame not assigned yet
this.turn=true;
this.score=0;
}
Here when you're accessing DataofGame, it's not yet assigned because you're inside the constructor when calling aSet().
What you want to achieve is not completely clear, but if it's adding an ASet method to your object, you could write something like this:
function newGameData(){
this.pointTeam1=0;
this.pointTeam2=0;
this.WordsoftheGame= ShuffleListe();
this.ASet = function() {
// your code
};
}
NB your coding style for names is a bit messy, you should use uppercases consistently. The usage is to start constructor names with uppercases, the rest in lower cases.
You can let the function return an object with the data or just set the object.
function newGameData(){
return {
pointTeam1 : 0,
pointTeam2 : 0,
WordsoftheGame : ShuffleListe(),
ASet : new aSet()
}
}
But I would recommend to search for how to work with objects in javascript. Maybe this helps:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

Prototypal Inheritance in Module Pattern JavaScript - Base Class not inheriting anything from parent

I just started to get into JS lately and I am using module pattern a lot and I really don't know if I am doing it right when it comes to doing inheritance from the module I wrote.
Here are the following .js files I am working on:
define(["src/Inhabitant"], function(Inhabitant)
{
console.log("Coin.js loaded");
return (function()
{
function Coin(stage , position)
{
Inhabitant.call(this, stage, position, "coinGold.png");
}
Coin.prototype =
{
prototype : Object.create(Inhabitant.prototype)
, constructor : Coin
, update : update
}
function update(elapsed)
{
}
return Coin;
})();
});
I have a JS class named as Coin and its parent is Inhabitant:
define([], function()
{
console.log("Inhabitant loaded.");
return (function()
{
var mStage = null;
var mSprite = null;
var mID = -1;
function Inhabitant(stage, position , resource)
{
mStage = stage;
mSprite = new PIXI.Sprite.fromFrame(resource);
mSprite.position = position;
}
Inhabitant.prototype =
{
constructor : Inhabitant
, get position(){ return mSprite.position; } , set position(position){ mSprite.position = position; }
, get x(){ return mSprite.x; } , set x(x){ mSprite.x = x; }
, get y(){ return mSprite.y; } , set y(y){ mSprite.y = y; }
, get id(){ return mID; } , set id(id){ return mID; }
, get sprite(){ return mSprite; }
, update : update
}
function update(elapsed)
{
console.log("Calling update from Inhabitant");
}
return Inhabitant;
})();
});
I am stuck on this one because I can't even call the methods I am supposed to inherit. Even the update function isn't provided by the parent. If I remove the update from Coin it will not call the parent version (I don't know if I have the correct assumption on this one).
Also most of the time I write my classes this way
define([] , function()
{
return function()
{
var o = {};
return o
}
});
This works most of the time since I am creating objects without the need of inheritance that much. But now I need to it in prototypal way so I can reduce code duplication.
What is the proper way of doing Module Pattern with prototypal inheritance given on what I currently have?
This have been asked many times via this link and this link but its not helping my situation.
Any ideas?

Incorporate window.onresize into OO JS class

I'm just trying to structure my Javascript better and wondering how to incorporate window.onresize into the returned object, like so:
var baseline = function(){
var tall, newHeight, target, imgl, cur, images = [];
return {
init: function(selector, target){
this.images = document.querySelectorAll(selector);
this.target = target;
this.setbase(this.images);
window.onresize = this.setbase(this.images);
},
setbase: function(imgs){
this.imgl = imgs.length;
if(this.imgl !== 0){
while(this.imgl--){
this.cur = imgs[this.imgl];
this.cur.removeAttribute("style");
this.tall = this.cur.offsetHeight;
this.newHeight = Math.floor(this.tall / this.target) * this.target;
this.cur.style.maxHeight = this.newHeight + 'px';
}
} else {
return false;
}
}
}
}();
Is this the way that people would do it, is this going to work? Thanks
EDIT:
Invoked like so:
window.onload = function(){
baseline.init('img', '24');
};
I would like it so that when the window is resized, baseline.init is called with the same params as the initial init function call...
Here's the main error
init: function(selector, target){
this.images = document.querySelectorAll(selector);
this.target = target;
this.setbase(this.images);
// This line says call setbase now and assign the result of that
// as the onresize handler
window.onresize = this.setbase(this.images);
},
Your this.images does not point to the var images = [] you've created. This is for when you're using protoype style objects. You should just use images in your functions.
Some of your variables look like they're only used in setBase, they should be local
Looking at your object, it's very hard to tell what it's supposed to do, sounds like you're wrapping code in an object just for the sake of wrapping it into an object. What does baseline mean?
Here's a better version of your code, you should read and understand http://www.joezimjs.com/javascript/javascript-closures-and-the-module-pattern/ and http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html so you can decide what pattern you want to use and how they actually work. You are mixing both patterns, even though you didn't intend to. The trick is that with the way you're writing it (module pattern) there's no need to use this in the code, they're actually local variables held be the module
var baseline = function(){
// Don't use "this.tall", just "tall" gets you the variable
// Class variables, are you sure you need them throughout the class
var tall, newHeight, target, imgl, cur, images = [];
// Different name for the parameter so it doesn't get confused with
// the class variables
function init(selector, pTarget) {
images = document.querySelectorAll(selector);
target = pTarget;
setBase();
// Since we're not using this, you
// can just reference the function itself
window.onresize = setBase
}
// Most JS developers name methods using camelCase
function setBase() {
imgl = imgs.length;
if(imgl !== 0){
while(imgl--){
cur = imgs[imgl];
cur.removeAttribute("style");
tall = cur.offsetHeight;
newHeight = Math.floor(tall / target) * target;
cur.style.maxHeight = newHeight + 'px';
}
// should you return true here? what does returning
// something even mean here?
} else {
return false;
}
}
// Return just the public interface
return {
init: init
setBase: setBase
};
}();

How can I make this javascript easier to read, maintain, and understand from an OO background?

I come from the land of Java, C#, etc. I am working on a javascript report engine for a web application I have. I am using jQuery, AJAX, etc. I am having difficulty making things work the way I feel they should - for instance, I have gone to what seems like too much trouble to make sure that when I make an AJAX call, my callback has access to the object's members. Those callback functions don't need to be that complicated, do they? I know I must be doing something wrong. Please point out what I could be doing better - let me know if the provided snippet is too much/too little/too terrible to look at.
What I'm trying to do:
On page load, I have a select full of users.
I create the reports (1 for now) and add them to a select box.
When both a user and report are selected, I run the report.
The report involves making a series of calls - getting practice serieses, leagues, and tournaments - for each league and tournament, it gets all of those serieses, and then for each series it grabs all games.
It maintains a counter of the calls that are active, and when they have all completed the report is run and displayed to the user.
Code:
//Initializes the handlers and reports
function loadUI() {
loadReports();
$("#userSelect").change(updateRunButton);
$("#runReport").click(runReport);
updateRunButton();
return;
$("#userSelect").change(loadUserGames);
var user = $("#userSelect").val();
if(user) {
getUserGames(user);
}
}
//Creates reports and adds them to the select
function loadReports() {
var reportSelect = $("#reportSelect");
var report = new SpareReport();
engine.reports[report.name] = report;
reportSelect.append($("<option/>").text(report.name));
reportSelect.change(updateRunButton);
}
//The class that represents the 1 report we can run right now.
function SpareReport() {
this.name = "Spare Percentages";
this.activate = function() {
};
this.canRun = function() {
return true;
};
//Collects the data for the report. Initializes/resets the class variables,
//and initiates calls to retrieve all user practices, leagues, and tournaments.
this.run = function() {
var rC = $("#rC");
var user = engine.currentUser();
rC.html("<img src='/img/loading.gif' alt='Loading...'/> <span id='reportProgress'>Loading games...</span>");
this.pendingOperations = 3;
this.games = [];
$("#runReport").enabled = false;
$.ajaxSetup({"error":(function(report) {
return function(event, XMLHttpRequest, ajaxOptions, thrownError) {
report.ajaxError(event, XMLHttpRequest, ajaxOptions, thrownError);
};
})(this)});
$.getJSON("/api/leagues", {"user":user}, (function(report) {
return function(leagues) {
report.addSeriesGroup(leagues);
};
})(this));
$.getJSON("/api/tournaments", {"user":user}, (function(report) {
return function(tournaments) {
report.addSeriesGroup(tournaments);
};
})(this));
$.getJSON("/api/practices", {"user":user}, (function(report) {
return function(practices) {
report.addSerieses(practices);
};
})(this));
};
// Retrieves the serieses (group of IDs) for a series group, such as a league or
// tournament.
this.addSeriesGroup = function(seriesGroups) {
var report = this;
if(seriesGroups) {
$.each(seriesGroups, function(index, seriesGroup) {
report.pendingOperations += 1;
$.getJSON("/api/seriesgroup", {"group":seriesGroup.key}, (function(report) {
return function(serieses) {
report.addSerieses(serieses);
};
})(report));
});
}
this.pendingOperations -= 1;
this.tryFinishReport();
};
// Retrieves the actual serieses for a series group. Takes a set of
// series IDs and retrieves each series.
this.addSerieses = function(serieses) {
var report = this;
if(serieses) {
$.each(serieses, function(index, series) {
report.pendingOperations += 1;
$.getJSON("/api/series", {"series":series.key}, (function(report) {
return function(series) {
report.addSeries(series);
};
})(report));
});
}
this.pendingOperations -= 1;
this.tryFinishReport();
};
// Adds the games for the series to the list of games
this.addSeries = function(series) {
var report = this;
if(series && series.games) {
$.each(series.games, function(index, game) {
report.games.push(game);
});
}
this.pendingOperations -= 1;
this.tryFinishReport();
};
// Checks to see if all pending requests have completed - if so, runs the
// report.
this.tryFinishReport = function() {
if(this.pendingOperations > 0) {
return;
}
var progress = $("#reportProgress");
progress.text("Performing calculations...");
setTimeout((function(report) {
return function() {
report.finishReport();
};
})(this), 1);
}
// Performs report calculations and displays them to the user.
this.finishReport = function() {
var rC = $("#rC");
//snip a page of calculations/table generation
rC.html(html);
$("#rC table").addClass("tablesorter").attr("cellspacing", "1").tablesorter({"sortList":[[3,1]]});
};
// Handles errors (by ignoring them)
this.ajaxError = function(event, XMLHttpRequest, ajaxOptions, thrownError) {
this.pendingOperations -= 1;
};
return true;
}
// A class to track the state of the various controls. The "series set" stuff
// is for future functionality.
function ReportingEngine() {
this.seriesSet = [];
this.reports = {};
this.getSeriesSet = function() {
return this.seriesSet;
};
this.clearSeriesSet = function() {
this.seriesSet = [];
};
this.addGame = function(series) {
this.seriesSet.push(series);
};
this.currentUser = function() {
return $("#userSelect").val();
};
this.currentReport = function() {
reportName = $("#reportSelect").val();
if(reportName) {
return this.reports[reportName];
}
return null;
};
}
// Sets the enablement of the run button based on the selections to the inputs
function updateRunButton() {
var report = engine.currentReport();
var user = engine.currentUser();
setRunButtonEnablement(report != null && user != null);
}
function setRunButtonEnablement(enabled) {
if(enabled) {
$("#runReport").removeAttr("disabled");
} else {
$("#runReport").attr("disabled", "disabled");
}
}
var engine = new ReportingEngine();
$(document).ready( function() {
loadUI();
});
function runReport() {
var report = engine.currentReport();
if(report == null) {
updateRunButton();
return;
}
report.run();
}
I am about to start adding new reports, some of which will operate on only a subset of user's games. I am going to be trying to use subclasses (prototype?), but if I can't figure out how to simplify some of this... I don't know how to finish that sentence. Help!
$.getJSON("/api/leagues", {"user":user}, (function(report) {
return function(leagues) {
report.addSeriesGroup(leagues);
};
})(this));
Can be written as:
var self = this;
$.getJSON("/api/leagues", {"user":user}, (function(leagues) {
self.addSeriesGroup(leagues);
});
The function-returning-function is more useful when you're inside a loop and want to bind to a variable that changes each time around the loop.
Provide "some" comments where necessary.
I'm going to be honest with you and say that I didn't read the whole thing. However, I think there is something about JavaScript you should know and that is that it has closures.
var x = 1;
$.ajax({
success: function () {
alert(x);
}
});
No matter how long time it takes for the AJAX request to complete, it will have access to x and will alert "1" once it succeeds.
Understand Closures. This takes some getting used to. (which, many will use, and is certainly the typical way of going about things, so it's good if you understand how that's happening)
This is a good thread to read to get a simple explanation of how to use them effectively.
You should use prototypes to define methods and do inheritance:
function Parent(x) {
this.x = x; /* Set an instance variable. Methods come later. */
}
/* Make Parent inherit from Object by assigning an
* instance of Object to Parent.prototype. This is
* very different from how you do inheritance in
* Java or C# !
*/
Parent.prototype = { /* Define a method in the parent class. */
foo: function () {
return 'parent ' + this.x; /* Use an instance variable. */
}
}
function Child(x) {
Parent.call(this, x) /* Call the parent implementation. */
}
/* Similar to how Parent inherits from Object; you
* assign an instance of the parent class (Parent) to
* the prototype attribute of the child constructor
* (Child).
*/
Child.prototype = new Parent();
/* Specialize the parent implementation. */
Child.prototype.foo = function() {
return Parent.prototype.foo.call(this) + ' child ' + this.x;
}
/* Define a method in Child that does not override
* something in Parent.
*/
Child.prototype.bar = function() {
return 'bar';
}
var p = new Parent(1);
alert(p.foo());
var ch = new Child(2);
alert(ch.foo());
alert(ch.bar());
I'm not familiar with jQuery, but I know the Prototype library (worst name choice ever) has some functionality that make it easier to work with inheritance.
Also, while coming up with the answer to this question, I found a nice page that goes into more detail on how to do OO right in JS, which you may want to look at.

Categories