So i have this mess of a js file
cardPool = []
class Card {
constructor(name = "", portrait = "", bloodCost = 0, boneCost = 0, power = 0, health = 1, sigilList = ["No sigil"]) {
this.name = name
this.portrait = portrait;
this.bloodCost = bloodCost;
this.boneCost = boneCost;
this.power = power;
this.health = health;
this.sigilList = sigilList;
cardPool.push(this)
}
Damage(dmg = 1) {
this.health -= dmg
}
}
blank = new Card("blank", "🔳");
income = new Card("income", "⬇️");
module.exports = {
Card,
blank,
income,
bear: function () { new Card("Grizzly", "🐻", 3, 0, 4, 6) },
wolf: function () { new Card("Wolf", "🐺", 2, 0, 3, 2) },
cardPool,
};
All I want to do is on start up it run all of the function being exported. There more function that I export but here only a few so stack overflow won't scream at me. This is for a game that I'm making to be able to handle multiple instance of the same card. You can read about why I make new card using function here: How to change a local class varible node js . And I need a card pool so that I can do stuff in another file here my other question: How can i put an object inside a list on Initialization. Now I need on startup put all the card that I make in the module.export in the cardPool.
The best way to do this would be placing the functions in some kind of container (for example an array or a map) (in case you later want to export other functions from the file that don't create cards). Here's the simplest way with an array:
// Note the return statements! The functions will not return anything without them!
function bear () { return new Card("Grizzly", "🐻", 3, 0, 4, 6) }
function wolf () { return new Card("Wolf", "🐺", 2, 0, 3, 2) }
module.exports = {
// ...
cardCreatorFunctions: [bear, wolf, /* and maybe others */],
}
Then, you can iterate through the array and push created cards into cardPool one-by-one:
for (let fun of cardLib.cardCreatorFunctions) {
cardLib.cardPool.push(fun())
}
Or you can do it in one statement:
cardLib.cardPool = cardLib.cardCreatorFunctions.map(fun => fun())
Related
I'm trying to add enemies to my platformer game using the matter physics engine however using the this.matter.world.on collisionactive function only checks collision between the floor and enemy after the player jumps once. I'm currently using labels to check for collision. I have tried adding extra conditions but have only been able to allow the player to infinitely jump. i.e- it is checking the labels of what is colliding.
Collision checking code:
this.matter.world.on("collisionactive", (e,o1,o2) => {
if(o1.label == 'floor' && o2.label == 'player')
{
this.touchingGround = true;
console.log('touching')
}
});
Enemy creation function:
Right now the enemies are cubes that are created at the cursor when the player presses f
function createEnemy(scene,x,y)
{
enemy = scene.matter.add.image(x,y,'enemy').setScale(1.5)
enemy.body.label = 'enemy'
}
I don't completely understand the problem, but if you have an issue with checking/finding all current collisions, you can use the pairs property of the event-object-argument (link to the documentation), which is passed to the physics-callback function. This property should contain, the other collisions.
"...The event.pairs array may contain more colliding bodies. ..."
Here a short demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 11 * 16,
height: 6 * 16,
zoom: 2,
pixelArt: true,
scene: {
preload: preload,
create: create
},
physics: {
default: 'matter',
matter: {
gravity: {
y:.3
},
debug:true
}
},
banner: false
};
function preload (){
this.load.image('mario-tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/super-mario.png');
}
function create (){
var level = [
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split('').map( _ => 14),
];
var map = this.make.tilemap({ data: level, tileWidth: 16, tileHeight: 16 });
var tiles = map.addTilesetImage('mario-tiles');
var layer = map.createLayer(0, tiles, 0, 0);
this.add.text(4, 4, 'click to jump', {color:'#9EE6FF', fontSize:10})
.setOrigin(0);
var info = this.add.text(4, 14, 'waiting ...', {color:'#ffffff', fontSize:10})
.setOrigin(0);
let enemy1 = this.add.rectangle(60.25, 5, 8, 8, 0xfff000)
.setOrigin(0.5);
let player = this.add.rectangle(60, 20, 8, 8, 0xffffff);
layer.setCollision([14]);
this.matter.add.gameObject(enemy1);
this.matter.add.gameObject(player);
this.matter.world.convertTilemapLayer(layer, {label:'floor'});
player.body.label = 'player';
enemy1.body.label = 'enemy';
this.input.on('pointerup', _=> player.setVelocityY(-3))
player.setVelocityY(-1)
this.matter.world.on("collisionactive", (e, o1, o2) => {
let text = 'p: ';
if( e.pairs.some (pair => pair.bodyA.label == 'player' && pair.bodyB.label =='floor' )) {
text += 'touch floor ';
}
if( e.pairs.some (pair => pair.bodyA.label == 'enemy' && pair.bodyB.label =='player' )) {
text += 'touch enemy ';
}
if( e.pairs.some (pair => pair.bodyA.label == 'enemy' && pair.bodyB.label =='floor' )) {
text += '\ne: touch floor';
}
info.setText(text);
});
}
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I'm trying to create something with P5.js that resembles an audio looper—that is, you record a snippet of audio, it plays back to you as a loop, and then you can record other snippets of audio to play together to create a song.
I figured out how to record audio, play it back as a loop, and stop the loop, but I'm not sure the best way to repeat that function so that it can be used for buttons that function independently of each other and record separate audio files, as I would like to record multiple loops.
I'm still pretty new to P5.js, so there's probably a simple way to do this—any ideas help! In general, if you have any ideas on how to achieve this project as a whole (the audio looper) I'd love to hear them.
This is my code:
let mic, recorder, soundFile, button;
let state = 0;
function setup() {
createCanvas(windowWidth, windowHeight);
background(200);
mic = new p5.AudioIn();
mic.start();
recorder = new p5.SoundRecorder();
recorder.setInput(mic);
soundFile = new p5.SoundFile();
button = createButton("record");
button.size(200, 100);
button.style("font-family", "Bodoni");
button.style("font-size", "48px");
button.position(10, 10, 10);
button.mouseClicked(loopRecord);
}
// this is the looper
function loopRecord() {
if (state === 0 && mic.enabled) {
recorder.record(soundFile);
background(255, 0, 0);
state++;
} else if (state === 1) {
recorder.stop();
background(0, 255, 0);
state++;
} else if (state === 2) {
soundFile.loop();
state++;
} else if (state === 3) {
soundFile.stop();
state++;
} else if (state === 4) {
state === 0;
}
}
You should somehow structure your data so that each button has its own state (and other parameters that should not be global, but instead unique to each loop).
Here an example using an array of track objects:
https://editor.p5js.org/RemyDekor/sketches/gM75vBYmk
I'll copy the code here as well
let mic
// this array will be filled afterwards
let tracksArray = [];
function setup() {
createCanvas(400, 400);
background(200);
// we need only one mic (it is still global)
mic = new p5.AudioIn();
mic.start();
// we call a function that creates a custom "track" object and puts it in the tracksArray (which you could use for some other things, but is currently un-used)
createTrack();
// we create a button that call the same function when we click on it
const addTrackButton = createButton("add track");
addTrackButton.mouseClicked(createTrack)
addTrackButton.position(10, 10)
}
// We now use names (strings) instead of abstract numbers to set the state of the track
function handleTrackButtonClick(trackObject) {
if (trackObject.state === "idle" && mic.enabled) {
trackObject.recorder.record(trackObject.soundFile);
background(255, 0, 0);
trackObject.state = "recording";
console.dir(trackObject.button.elt.innerText = "[recording..]");
} else if (trackObject.state === "recording") {
trackObject.recorder.stop();
background(0, 255, 0);
trackObject.state = "stopped";
console.dir(trackObject.button.elt.innerText = "play");
} else if (trackObject.state === "stopped") {
trackObject.soundFile.loop();
trackObject.state = "playing";
console.dir(trackObject.button.elt.innerText = "[playing..] stop")
} else if (trackObject.state === "playing") {
trackObject.soundFile.stop();
trackObject.state = "stopped";
console.dir(trackObject.button.elt.innerText = "[stopped..] play")
}
}
function createTrack() {
const newButton = createButton("record");
newButton.style("font-family", "Bodoni");
newButton.style("font-size", "48px");
// we do not position this button anymore, and use the "flow" of the html document
newButton.style("display", "block");
// this is the "track" object we create, and we attach the previously global parameters/states on it
const newTrackObject = {
button: newButton,
state: "idle",
recorder: new p5.SoundRecorder(),
soundFile: new p5.SoundFile()
};
newButton.mouseClicked(function() {
handleTrackButtonClick(newTrackObject)
});
newTrackObject.recorder.setInput(mic);
tracksArray.push(newTrackObject);
}
I'm trying to load multiple sliders using noUISlider and it's not working. When using the first slider, the values changes for the second and third. How do I go about refactoring the code for one slider so I can easily add additional sliders with different options?
Here's a fiddle and below is my code.
// noUISlider
var actSlider = document.getElementById('act-slider');
noUiSlider.create(actSlider, {
start: [0, 50],
connect: false,
step: 1,
range: {
'min': 0,
'max': 50
},
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
// Connect bar
var connectBar = document.createElement('div'),
connectBase = actSlider.getElementsByClassName('noUi-base')[0],
connectHandles = actSlider.getElementsByClassName('noUi-origin');
// Give the bar a class for styling and add it to the slider.
connectBar.className += 'connect';
connectBase.appendChild(connectBar);
actSlider.noUiSlider.on('update', function (values, handle) {
// Pick left for the first handle, right for the second.
var side = handle ? 'right' : 'left',
// Get the handle position and trim the '%' sign.
offset = (connectHandles[handle].style.left).slice(0, -1);
// Right offset is 100% - left offset
if (handle === 1) {
offset = 100 - offset;
}
connectBar.style[side] = offset + '%';
});
// Value tooltips
var tipHandles = actSlider.getElementsByClassName('noUi-handle'),
tooltips = [];
// Add divs to the slider handles.
for (var i = 0; i < tipHandles.length; i++) {
tooltips[i] = document.createElement('div');
tooltips[i].className += 'value-tooltip';
tipHandles[i].appendChild(tooltips[i]);
}
// When the slider changes, write the value to the tooltips.
actSlider.noUiSlider.on('update', function (values, handle) {
tooltips[handle].innerHTML = values[handle];
});
You can wrap your slider creation in a function, and call it for all elements where you want a slider created.
noUiSlider also supports tooltips (from version 8.1.0) and connect options, so you don't have to implement those yourself if you don't want to make very specific changes.
As for different options for every slider, there are several ways to do this. I've added an example using data attributes for the step option.
The following code initializes a slider on all elements with a .slider class.
function data ( element, key ) {
return element.getAttribute('data-' + key);
}
function createSlider ( slider ) {
noUiSlider.create(slider, {
start: [0, 50],
connect: false,
step: Number(data(slider, 'step')) || 1,
range: {
'min': 0,
'max': 50
},
tooltips: true,
connect: true,
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
}
Array.prototype.forEach.call(document.querySelectorAll('.slider'), createSlider);
Here's a jsFiddle demonstrating this code.
I have this function
var textHowTo;
this.drawString = function(textToDraw, props, color, posX, posY, containerbox, lineW, aligns)
{
console.log("Draw String");
var textContent_1 = textToDraw;
textHowTo = new createjs.Text(textContent_1, props, color);
var w = ( textHowTo.getMeasuredWidth() ) * textHowTo.scaleX;
var h = ( textHowTo.getMeasuredHeight() ) * textHowTo.scaleY;
//textHowTo.regY = h / 2;
textHowTo.textAlign = aligns;
if (lineW > 0)
textHowTo.lineWidth = lineW;
//textHowTo.font = 'assets/fonts/Elite Hacker (Corroded).ttf';
textHowTo.x = posX;
textHowTo.y = posY;
containerbox.addChild(textHowTo);
}
textHowTo is my global text Instance
and on the init page I called it like this :
this.GS_Gameplay_Init = function ()
{
module.drawString( TEXT.EN.GP_TEXT_TUTORIAL_1 , "30px Hacker", "#ffffff", (FAR_ANCHOR<<1)+50, (FAR_ANCHOR<<1) + 100, finish_containerbox, 300, 'center');
module.drawString( TEXT.EN.GP_TEXT_TUTORIAL_2 , "15px Hacker", "#ffffff", (FAR_ANCHOR<<1)+50, (FAR_ANCHOR<<1) + 250, finish_containerbox, 200, 'center');
}
My question how do I remove both of them?
I have tried using this :
finish_containerbox.removeChild(textHowTo);
But only the last text(TEXT.EN.GP_TEXT_TUTORIAL_2 ) removed.
Anyone can help me?
To build on #Barman's answer, you need to save references to your instances so you can remove them later.
If you're dealing with an indeterminate number of instances, then you'll probably want to use an array.
var textInstances = [];
// ...
textInstances.push(this.drawString(...)); // drawString should return the instance
// ...
while (textInstances.length) {
var text = textInstances.pop();
text.parent.removeChild(text);
}
You could use
finish_containerbox.removeAllChildren();
or have your function 'drawString' return the instance
this.myText1 = this.drawString(..);
this.finish_containerbox.addChild(this.myText1);
this.myText2 = this.drawString(..);
this.finish_containerbox.addChild(this.myText2);
and later use these vars to remove the instance:
this.finish_containerbox.removeChild(this.myText1);
this.finish_containerbox.removeChild(this.myText2);
is there a recommended way to deep compare 2 arrays in yui3 tests (similar to QUnit's deepEqual)? I poked around the source and the best I could come up with was to steal this function from matrix/matrix.js (shown slightly rewritten) It could easily be modified to a recursive arbitrary depth comparison, but I'm digressing now...
function compare(list1, list2)
{
var i = 0, len = list1.length, len2 = list2.length, isEqual = len === len2;
if(isEqual) {
for(; i < len; ++i) {
if(list1[i] != list2[i]) {
isEqual = false; break;
}
}
}
return isEqual;
}
Yes, YUI Tests have an Test.ArrayAssert namespace where you have many assertions for arrays. In particular you have itemsAreEqual which tests with == and itemsAreEquivalent which uses ===. You get this for free by including the test module.
YUI().use('test', function (Y) {
var ArrayAssert = Y.Test.ArrayAssert;
var testCase = new Y.Test.Case({
name: "TestCase Name",
//traditional test names
testSomething : function () {
ArrayAssert.itemsAreEqual([1, 2, 3], foo, 'all items should be 1, 2, 3');
}
});
});