I have been bashing my head on this and I know that it's probably an easy fix but I can't for the life of me figure out what is wrong. I am trying to call a class function within a for loop and I've tried a few methods but i've come up with diddly-squat so far. I'll plug in the relevant snippets below. For reference this is a project to make a web-based simple game and I've chosen a bastardization of galaga and asteroids hence, "ship" and "asteroids." My question is why won't it populate the class function .spawn(); that's been assigned to the items in the "rock" iterative? Any advice would be extremely helpful.
var rock = []; //I know global variables = evil, but I'm still early in development
function setup() {
...
//Asteroids
for(var i = 0; i<5; i++){
var y = random(0,350);
var speed = random(2,5);
rock.push(new asteroid(800,y,speed,10));
}
...
}
function draw() {
...
//Spawn Asteroids
//rock[0].spawn(); //<-------Single instance of object from array(works as intended)
/*for (let c of rock){ //<-------Tried changing variable type to const as well because I was pulling my hair out and that did nothing either.
this.spawn();
}*/
/*for (let c in rock){ //<-------Covering my bases
this.spawn();
}*/
rock.forEach(index => this.spawn()); //<------Last thing I tried
...
}
//////////////////////////////////////////////////////////////////////////////
class asteroid {
...
spawn(){
this.move();
this.display();
this.offScreen();
this.speed = random(2,5);
}
...
}
////////////////////////////////////////////////////////////////////////////////////////////
Note: I tried to create a facsimile of another for loop that I used for
the ship attack but it didn't work either. It's this snippet below.
draw(){
this.bullets.forEach((bullet) => {
if(this.isBulletOffScreen(bullet)){
const index = this.bullets.indexOf(bullet);
this.bullets.splice(index, 1);
}
bullet.draw();
});
}
I don't have the one I tried to adapt because I felt I was way over complicating a simple object so I erased it but this is the working code for the projectile controller class that I was copying from.
P.S. Here is the Error message I keep getting.
*🌸 p5.js says: [sketch.js, line 86] "spawn" could not be called as a function. Verify whether "this" has "spawn" in it and check the
spelling, letter-casing (JavaScript is case-sensitive) and its type.
More info: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_a_function#What_went_wrong
sketch.js:86*
** Uncaught TypeError: this.spawn is not a function
at draw (sketch.js:86:10)
at p5._main.default.redraw (p5.js:71990:27)
at _draw (p5.js:64140:25) ​**
#Teemu had the answer and it took a bit for my thick skull to work it out. By adjusting the forEach to resemble this:
rock.forEach(index => index.spawn());
They spawn and now I can start moving forward again. Thank you again Teemu!
Related
So, I'm familiar with the general gist of JavaScript's features regarding objects. They're refcounted and if they go to zero, they die. Additionally, apple = banana where both are objects doesn't copy banana to apple but makes apple a reference to banana.
That being said, some of my code has something like this:
// imagine ws require() and setup here...
var RateLimit = require("ws-rate-limit")('10s', 80);
SickWebsocketServer.on("connection", function(mysocket, req){
// blahblahblah...
RateLimit(mysocket); // See below...
mysocket.on("limited", function(){console.log("someone was limited!"});
mysocket.on("message", function(data){
if(JSON.parse(msg).MyFlagToMessageASpecificWebsocketClient){ // obvs dont do this lol
findme = MyArr.find(guy=>guy.Socket==mysocket);
if(findme) console.log("TRIGGER PLS :)"); // GOAL
else console.log("DON'T TRIGGER"); // SOMETHING WENT WRONG
}
});
MyArr.push({MyName:"my SICK object", MyNumber:MyArr.length, Socket:mysocket})
}
The library used for rate limiting is called ws-rate-limit and I have pasted a shortened (non-code removed) version down below (since it's tiny). Imagine it to be in a package called ws-rate-limit (because it is :D).
const duration = require('css-duration')
module.exports = rateLimit
function rateLimit (rate, max) {
const clients = []
// Create an interval that resets message counts
setInterval(() => {
let i = clients.length
while (i--) clients[i].messageCount = 0
}, duration(rate))
// Apply limiting to client:
return function limit (client) {
client.messageCount = 0
client.on('newListener', function (name, listener) {
if (name !== 'message' || listener._rated) return
// Rate limiting wrapper over listener:
function ratedListener (data, flags) {
if (client.messageCount++ < max) listener(data, flags)
else client.emit('limited', data, flags)
}
ratedListener._rated = true
client.on('message', ratedListener)
// Unset user's listener:
process.nextTick(() => client.removeListener('message', listener))
})
// Push on clients array, and add handler to remove from array:
clients.push(client)
client.on('close', () => clients.splice(clients.indexOf(client), 1))
}
}
My issue is that, when I do use the RateLimit function, the "DON'T TRIGGER" code triggers. If I literally remove that one single line (RateLimit(mysocket)) it goes into "TRIGGER PLS :)".
The above is obviously logically simplified from my actual application but I think you get the gist. Apologies for any misspellings that may lead to undefineds or stuff like that; I promise you my code works if not for the RateLimit(mysocket) line.
When I add console.logs into the find function to log both the guy.Socket object and the mysocket object, with the RateLimit(mysocket) line, the mysocket object's .toString() returns [object global] rather than [object Object]. I know that this is some complicated JavaScript object scoping problem, but I have no clue where to start in terms of investigating it.
Thank you! :)
I'll take a random shot in the dark based on intuition. My best guess is that your issue is with the guy.Socket==mysocket line. Comparing objects that way will only check if they both point to the same heap memory location, even if it's two different stack variables. In your example I can only assume that the RateLimit(mysocket) line is somehow creating a new heap location for that stack variable (creating a new object from it) and because of that your == comparison is then no longer equal (even if they have the exact same values) because they're pointing to different locations.
Try using: JSON.stringify(guy.socket) === JSON.stringify(mysocket).
I've created a memory game. Most of the functions work, but one thing I'm struggling with is getting the cards to flip correctly. Here is the function I'm using to swap between the back of the card (card.jpg) and the front of the card (image names found in the ImagesArr array):
// Swap out cards for shuffled images
function swapImages() {
for(var i = 0; i < images.length; i++) {
if(images[i].src !== "/img/card.jpg") {
images[i].src = imagesArr[i];
} else {
images[i].src = "/img/card.jpg";
}
}
}
It works to show the hidden images, but it shows ALL of them, not just the one that's clicked. I also have this function above it which helps with the flip animation and adding some necessary classes as well as calling the swapImages function.
// Flip the cards over on click and start the timer
function flipCards() {
cards.forEach(card => {
card.addEventListener("click", () => {
card.classList.toggle("flipped");
card.classList.toggle("chosen");
chosenCards.push(card);
startTimer();
swapImages();
checkMatch();
});
});
}
I feel like I need a forEach loop or something like that, but I'm not sure how to implement it or where to implement it. I also could be completely wrong and don't need a forEach loop at all. TIA for any help!
I think that you need to use target event (https://www.w3schools.com/jsref/event_target.asp). So that program know which card is on other side .By the code that you provided l suspect that on click all cards flip.
For my current game-development project, I'm using pure JS and HTML5 Canvas, no jQuery, nothing of the sort.
I have X images to load at the beginning of a level. So far, I've been using the load handler on them to increment a counter (which counts how many images are loaded) until the counter value is X.
Once it's done, it begins to draw things on the Canvas.
Now, I've reached the stage where I'm trying to pass as much stuff into it's own specific class as possible. My issue is that if I put all the loaders into the classes, I'm not sure how I can check if that counter is at the correct value.
My idea was to create something like this:
In GameLevel.js:
function init(player,level,actors,enemies)
var loaded_components = 0;
if (player.initializeImages==true)
loaded_components++;
if (level.initializeImages==true)
loaded_components++;
(...)
if (loaded_components==5)
initiateDrawing();
In, for example, Player.js:
initializeImages(){
loaded=0;
maxload=10;
this.idle.addEventListener("load",loadHandler);
this.idle.id = "idle";
this.idle.src = "path/idle.png";
(...)
loadHandler(ev){
if (ev.id == "idle")
loaded++;
(...)
if (loaded==maxLoad){
return true;
}
}
}
So, the issue here is: I'm not sure how to make the code stop at that test for the return value of the initializeImage() method. I want the loading of all things to be placed within the specific class of the thing being loaded, if that makes sense.
I also know that you can load things without checking, and I've been doing that with the audio to test, but it's unsafe, and I really want to change it! I'm rather new to it, but if anyone has a solution that works, I'd love to hear about it.
Thanks in advance!
Edit: Tried it, but I'm failing!
I have a class that receives a few Canvasses, draws to them, and only once these are drawn should the code move forward.
I tried making a promise within the constructor, so it would be:
constructor(layer1,layer2,layer3,layer4){
this.layer1 = layer1;
(...)
var promise = new Promise(function(resolve,reject){
**(load everything here)**
**(once everything is loaded, draw to the
multiple canvasses referenced above)**
**(all done, resolve)**
});
}
This didn't work. I tried making the promise outside, in GameLevel.js, in the following way:
(in gameLevel):
var promise = new Promise(..){
scene = new Scene(layer1, layer2 (...))
resolve("done");
promise.then(function(){
beginGame();
}
This also does not work, the promise isn't... Waiting, for the scene to finish it's full creation and initialization. What am I doing wrong?
Here is a example with loading and rendering loop.
function loadimage(src){
return new Promise(resolve=>{
let img = new Image();
img.onload = ()=>resolve(img)
img.src=src
})
}
function stageinit(){
let imagesPromise = [
loadimage('https://via.placeholder.com/150'),
loadimage('https://via.placeholder.com/300')
]
return Promise.all(imagesPromise)
}
stageinit().then(images=>{
//images are loaded, do whatever you want
let canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')
let x = 0
function gameloop(){
requestAnimationFrame(gameloop)
ctx.fillRect(0,0,500,500)
ctx.drawImage(images[0],x,0)
ctx.drawImage(images[1],x,200)
x+=1
}
gameloop()
}
)
canvas{width:80vmin;height:80vmin;border:3px solid yellow}
<canvas width=500 height=500></canvas>
In Screeps, I this code doesn't work:
var sources = creep.room.find(Game.FIND_SOURCES_ACTIVE);
It says this:
Cannot read property 'find' of undefined
I have been looking around and cannot find ANY other way to find sources.
Also I've noticed that most of other peoples code doesn't work and even the tutorial's code no longer works when put into the real game.
I can't be completely sure about your issue since I don't have your complete code to go off of but one issue could be that creepis not defined.
You need somewhere in your code to define creep such as a for loop to loop over each of your creeps in the game or room.
var roleMiner = require('role.miner') // role.miner being the module name for miner actions
for(var name in Game.creeps) {
var creep = Game.creeps[name];
//
// do whatever you wish with the current selected creep.
//
// most of the time you will call a module similar to what the tutorials suggest and put your actions for it in there
//
if(creep.memory.role == 'miner'){
roleMiner.run(creep); // passes the current selected creep to the run function in the module
}
}
So, in your roleMiner module you would have something that defines your miners actions.
var roleMiner = {
run: function(creep) {
// this one returns an array of the sources that are in the room with the creep
var sourcesRoom = creep.room.find(FIND_SOURCES);
// this one returns the source object which is closest to the creeps positon
var sourcesClose = creep.pos.findClosestByRange(FIND_SOURCES);
}
}
module.exports = roleMiner;
Hope this helps.
Screeps have some ... mechanism when sharing your data between each game tick.
If you store any thing in global Memory object, your data will lose all its prototype.
to restore your prototype use Object.setPrototypeOf(creep,Creep.prototype) or create new Creep object from your creep id.
I think what you are looking for is:
var sources = creep.pos.findClosestByRange(Game.SOURCES);
or
var sources = creep.pos.findClosestByPath(Game.SOURCES);
im a new player, not sure my code is efficient, i think the find method will be like this:
var sources = creep.room.find(FIND_SOURCES_ACTIVE)
creep will going to the active resource to harvester.
I'm trying to use infinite-scroll to lazy load images. I'm getting the following error when it's called though:
TypeError: undefined is not a function
at handler (http://onfilm.us/ng-infinite-scroll.js:31:34)
Here's a very watered down look of what I have thus far.
function tagsController($scope) {
$scope.handleClick = function(tags) {
// Parse Tags
$scope.finished_tags = parsed_data;
};
$scope.$emit( 'handleEmit', { tags = $scope.finished_tags; });
};
function imagesController($scope,$http) {
var rows_per = 5;
$scope.$on('handleBroadcast', function(event, args) {
// Sort the images here, put them in matrix
// Example: matrix[row_number] = { picture1, picture2, picture3 }
$scope.data = matrix;
$scope.loadMore();
};
$scope.loadMore() = function() {
var last = $scope.images.length;
for ( var i = 0; i < rows_per; i++ ) {
$scope.images[last + i] = new Array();
$scope.images[last + i] = $scope.data[last + i].slice( 0 );
}
}
}
The rough idea is that the page loads the first time (w/ no tags) and get images from a PHP script. All of them. They are stored, and loadMore() is called which will populate $scope.images with 5 rows of images. It does, and they are loaded.
The line in that script is accessing $window.height and $window.scrollup. I'm still pretty green w/ Javascript, so feel free to lambast me if I'm doing something horribly wrong.
This is the broken version I'm testing with:
http://onfilm.us/test.html
Here is a version before the lazy loading was implemented, if seeing how the tags work will help. I don't think that's the issue here though.
http://onfilm.us/image_index.html
EDIT: I do think this is a problem w/ the ng-infinite-scroll.js script. The error is on line 31 (of version 1.0.0). It's telling me:
TypeError: undefined is not a function
It doesn't like $window apparently.
My JS Kung Fu is not really equipped to say why. YOu can see a literal copy/paste job from the simple demo here (with the error) onfilm.us/scroll2.html
By refering your site, It appears at first instance that your HTML-markup is not appropriate. You should move infinite-scroll to the parent of ng-repeat directive so that it will not make overlapping calls for each row generated. Please visit http://binarymuse.github.io/ngInfiniteScroll/demo_basic.html