How can I turn off the sound from another scene? - javascript

I attached music file to my first scene and thanks to following javascipt code, sound continues without stopping in other scenes.
public static var object : SingletonMusic = null;
function Awake()
{
if( object == null )
{
object = this;
DontDestroyOnLoad(this);
}
else if( this != object )
{
Destroy( gameObject );
}
}
My problem is that I want to turn off the sound from the button in the another scene (setting scene) so that I added a new button to my setting scene and attached the following javascript code to the button that I have created.
Javascript code:
var objects: AudioSource = SingletonMusic.object.GetComponent(AudioSource);
if( objects.isPlaying )
objects.Pause();
else
objects.Play();
However, it gives following errors:
If I start the game from Setting scene; I get this error:
If I start the game from first scene and then, go to Setting scene; I get this error:

Related

Phaser - error: Cannot read property 'on' of null

I'm working on a simple game using Phaser.
My code:
preload() {
this.load.image('player', 'img/player.png');
}
create() {
var player = this.add.sprite(100,100,'player');
player.inputEnabled = true;
player.input.on('pointerdown', () => {
this.scene.stop('ThisScene');
this.scene.start('NextScene');
})
}
The game should switch from one scene to another when you click on the sprite 'player'. Unfortunately, this gives an error: Cannot read property 'on' of null
Any ideas?
The reason it doesn't work is that you've got a mixture of Phaser 2 and Phaser 3 code here. The inputEnabled = true comes from Phaser 2, and the use of the on event listener is from Phaser 3.
You don't state which version you're using, though, so I'll assume 3 and fix the code for that:
preload() {
this.load.image('player', 'img/player.png');
}
create() {
var player = this.add.sprite(100,100,'player');
player.setInteractive();
player.on('pointerdown', () => {
this.scene.start('NextScene');
})
}
When a Game Object is enabled for input, you listen for the events directly on the Game Object itself, not the input component.
Have you check if the pointerdown event is working? Let's try to replace the line player.inputEnabled = true; with the line player.setInteractive();. Then, do a console.log('pointerdown event working') inside the event listener:
create() {
var player = this.add.sprite(100,100,'player');
player.setInteractive();
player.input.on('pointerdown', () => {
console.log('pointerdown event working');
this.scene.stop('ThisScene');
this.scene.start('NextScene');
})
}
Let me know if that works...If not, we'll know that the event is firing & we'll take it from there.

phaser.js, javascript, Uncaught TypeError: Cannot read property 'forEach' of undefined

I'm a beginner on Phaser.js and Javascript. I'm making a game and I've a bug that I can't figure how to fix it.
I think I can explain why it is happening : when i debug the phisics group SpritesPlatform shows that it's not undefined .. I don't know why ..
here the file where I've the bug ( I can't put the entire application here cause there's many files, but the problem concerns this file only, and the sprites are loaded in another file ).
file game.js (main.js)
MyGame.Game = function (game) {
this.game; // a reference to the currently running game (Phaser.Game)
this.add; // used to add sprites, text, groups, etc (Phaser.GameObjectFactory)
this.load; // for preloading assets (Phaser.Loader)
this.stage; // the game stage (Phaser.Stage)
this.state; // the state manager (Phaser.StateManager)
this.world; // the game world (Phaser.World)
this.physics; // the physics manager (Phaser.Physics)
};
MyGame.Game.prototype = {
init: function () {
this.game.renderer.renderSession.roundPixels = true;
this.physics.startSystem(Phaser.Physics.ARCADE);
this.physics.arcade.gravity.y = 800;
},
create: function () {
// background color bleu
this.stage.backgroundColor = 0x479cde;
//add sprites into physics group
SpritesPlatform = this.game.add.physicsGroup();
a = SpritesPlatform.create(0, 150, 'sprite');
a.scale.setTo(0.2, 0.2);
b = SpritesPlatform.create(79, 187, 'sprite2');
b.scale.setTo(0.2, 0.2);
c = SpritesPlatform.create(300, 100, 'sprite3');
c.scale.setTo(0.4, 0.4);
SpritesPlatform.setAll('body.allowGravity', false);
SpritesPlatform.setAll('body.immovable', true);
SpritesPlatform.setAll('body.velocity.x', 150);
//test to see if the group contains the sprites
/*var i = 0;
for (var i = 0, len = SpritesPlatform.children.length; i < len; i++) {
console.log(SpritesPlatform.children[i]);
}*/
//debug
console.log(this.game.SpritesPlatform); // prints undefined .. why???
},
// repeat the mouvement of the sprites when it crosses the screen
wrapSprites: function (SpritesPlatform) {
if (SpritesPlatform.body.velocity.x < 0 && SpritesPlatform.x <= -160)
{
SpritesPlatform.x = 800;
}
},
update: function () {
console.log(this.game.SpritesPlatform); // prints undefined also of course... ?? why??
//the error is here ... if i put this in comment the code will display the board and the sprite ...
//this.game.SpritesPlatform.forEach(this.game.wrapSprites, this.game);
},
};
the problem is in the update function in the line : //this.game.SpritesPlatform.forEach(this.game.wrapSprites, this.game);
It looks like the SpritesPlatform is undefined, and i don't understand why and what i'm missing.
thank u for any help.
When you first create the group, you have to declare it like that:
this.SpritesPlatform = this.game.add.physicsGroup();
and whenever you want to refer to this group you can do it with console.log(this.SpritesPlatform)
Edit:
You don't actually have to do anything like that
MyGame.Game = function (game) {
this.game; // a reference to the currently running game (Phaser.Game)
this.add; // used to add sprites, text, groups, etc (Phaser.GameObjectFactory)
this.load; // for preloading assets (Phaser.Loader)
this.stage; // the game stage (Phaser.Stage)
this.state; // the state manager (Phaser.StateManager)
this.world; // the game world (Phaser.World)
this.physics; // the physics manager (Phaser.Physics)
};
All those properties are readily accessible, so you can just use them wherever you want inside a state. This should work just fine:
MyGame.Game = function () {
};

Playing audio files from object array in js/jquery

I'm working on making an object to wrap controls around instances of html5 audio elements. For testing, I've made an object like this (simplified for readability)..
function AudioObject(audio) {
var innerAudio = audio;
this.Play = function () {
innerAudio.play()
}
}
And I have an array holding instances of this AudioObject.
var AudioObjects = [];
Then, when creating new AudioObjects, I add them to the array. I have a function that plays the AudioObjects with delays so they play in sequence. Something like this:
var audioObj = new AudioObject(audio);
AudioObjects.push(audioObj);
....
....
var delay = 0;
$.each(AudioObjects, function(iterator, obj) {
setTimeout(obj.Play, delay);
delay = delay + 3000;
}
When there is just one audio file, it plays correctly, but once I add more AudioObjects, each one in the array has their innerAudio variable set to the latest created Audio element. I can play each one individually from the html. I've debugged on creation and I can see it's setting the right audio, but after being pushed to the array, the objects in the array all get switched to the latest innerAudio.
Am I not instantiating my objects correctly? I've made this jsfiddle to experiment with alerting text, and it doesn't seem to have the issues I'm experiencing.
Update: I think I found my issue. This is how I thought you write a "public" and a "private" function inside of an object.
function Thing(test) {
var thingTest = test;
// Public function
this.PublicTest = function () {
setTimeout(Test, 1000);
}
// Private function
PrivateTest = function () {
alert(thingTest);
}
}
This is essentially how my code was structured, but the "private" function has a different scope than the public one. I double-checked my array, and it was actually saving the right audioObject with the correct audio source, but when running the function that calls the "private" function, it calls the wrong audio file.
I've updated the jsfiddle to show what's happening. I thought it would alert "test1" then "test2" but it alerts "test2" twice.
Update 2: For the record, changing the private function to this fixed the problem:
function Play() { // <<< That's all I had to change!
innerAudio.play()
}
Do you create unique aduio object for each audio wrapper?
var audio = new Audio();
audio.src = 'src';
var audioObj = new AudioObject(audio);
AudioObjects.push(audioObj);

ThreeJS: Remove object from scene

I'm using ThreeJS to develop a web application that displays a list of entities, each with corresponding "View" and "Hide" button; e.g. entityName View Hide. When user clicks View button, following function is called and entity drawn on screen successfully.
function loadOBJFile(objFile){
/* material of OBJ model */
var OBJMaterial = new THREE.MeshPhongMaterial({color: 0x8888ff});
var loader = new THREE.OBJLoader();
loader.load(objFile, function (object){
object.traverse (function (child){
if (child instanceof THREE.Mesh) {
child.material = OBJMaterial;
}
});
object.position.y = 0.1;
scene.add(object);
});
}
function addEntity(object) {
loadOBJFile(object.name);
}
And on clicking Hide button, following function is called:
function removeEntity(object){
scene.remove(object.name);
}
The problem is, entity is not removed from screen once loaded when Hide button is clicked. What can I do to make Hide button to work?
I did small experiment. I added scene.remove(object.name); right after scene.add(object); within addEntity function and as result, when "View" button clicked, no entity drawn (as expected) meaning that scene.remove(object.name); worked just fine within addEntity. But still I'm unable to figure out how to use it in removeEntity(object).
Also, I checked contents of scene.children and it shows: [object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Complete code: http://devplace.in/~harman/model_display1.php.html
Please ask, if more detail is needed. I tested with rev-59-dev and rev-60 of ThreeJS.
Thanks. :)
I think seeing your usage for addEntity and removeEntity code would be helpful, but my first thought is are you actually setting the object.name? Try in your loader just before scene.add(object); something like this:
object.name = "test_name";
scene.add(object);
What might be happening is the default "name" for an Object3D is "", so when you then call your removeEntity function it fails due to the scene objects name being ""
Also, I notice you pass in object.name to your loader? Is this where your storing the URL to the resource? If so, I would recommend using the Object3D's built in .userData method to store that information and keep the name field for scene identification purposes.
Edit: Response to newly added Code
First thing to note is it's not a great idea to have "/" in your object name, it seems to work fine but you never know if some algorithm will decide to escape that string and break your project.
Second item is now that I've seen your code, its actually straight forward whats going on. Your delete function is trying to delete by name, you need an Object3D to delete. Try this:
function removeEntity(object) {
var selectedObject = scene.getObjectByName(object.name);
scene.remove( selectedObject );
animate();
}
Here you see I lookup your Object3D in the Three.js Scene by passing in your object tag's name attribute.
clearScene: function() {
var objsToRemove = _.rest(scene.children, 1);
_.each(objsToRemove, function( object ) {
scene.remove(object);
});
},
this uses undescore.js to iterrate over all children (except the first) in a scene (it's part of code I use to clear a scene). just make sure you render the scene at least once after deleting, because otherwise the canvas does not change! There is no need for a "special" obj flag or anything like this.
Also you don't delete the object by name, just by the object itself, so calling
scene.remove(object);
instead of scene.remove(object.name);
can be enough
PS: _.each is a function of underscore.js
I came in late but after reading the answers more clarification needs to be said.
The remove function you wrote
function removeEntity(object) {
// scene.remove(); it expects as a parameter a THREE.Object3D and not a string
scene.remove(object.name); // you are giving it a string => it will not remove the object
}
A good practice to remove 3D objects from Three.js scenes
function removeObject3D(object3D) {
if (!(object3D instanceof THREE.Object3D)) return false;
// for better memory management and performance
if (object3D.geometry) object3D.geometry.dispose();
if (object3D.material) {
if (object3D.material instanceof Array) {
// for better memory management and performance
object3D.material.forEach(material => material.dispose());
} else {
// for better memory management and performance
object3D.material.dispose();
}
}
object3D.removeFromParent(); // the parent might be the scene or another Object3D, but it is sure to be removed this way
return true;
}
If your element is not directly on you scene go back to Parent to remove it
function removeEntity(object) {
var selectedObject = scene.getObjectByName(object.name);
selectedObject.parent.remove( selectedObject );
}
THIS WORKS GREAT - I tested it
so, please SET NAME for every object
give the name to the object upon creation
mesh.name = 'nameMeshObject';
and use this if you have to delete an object
delete3DOBJ('nameMeshObject');
function delete3DOBJ(objName){
var selectedObject = scene.getObjectByName(objName);
scene.remove( selectedObject );
animate();
}
open a new scene , add object
delete an object and create new
I started to save this as a function, and call it as needed for whatever reactions require it:
function Remove(){
while(scene.children.length > 0){
scene.remove(scene.children[0]);
}
}
Now you can call the Remove(); function where appropriate.
When you use : scene.remove(object);
The object is removed from the scene, but the collision with it is still enabled !
To remove also the collsion with the object, you can use that (for an array) :
objectsArray.splice(i, 1);
Example :
for (var i = 0; i < objectsArray.length; i++) {
//::: each object ::://
var object = objectsArray[i];
//::: remove all objects from the scene ::://
scene.remove(object);
//::: remove all objects from the array ::://
objectsArray.splice(i, 1);
}
I improve Ibrahim code for removeObject3D, added some checks for geometry or material
removeObject3D(object) {
if (!(object instanceof THREE.Object3D)) return false;
// for better memory management and performance
if (object.geometry) {
object.geometry.dispose();
}
if (object.material) {
if (object.material instanceof Array) {
// for better memory management and performance
object.material.forEach(material => material.dispose());
} else {
// for better memory management and performance
object.material.dispose();
}
}
if (object.parent) {
object.parent.remove(object);
}
// the parent might be the scene or another Object3D, but it is sure to be removed this way
return true;
}
this example might give you a different approach . I was trying to implement a similar feature in my project also with scene.remove(mesh). However disposal of geometry and material attributes of mesh worked for me!
source
Use
scene.remove(Object)
The object you want to remove from the scene
I had The same problem like you have. I try this code and it works just fine:
When you create your object put this object.is_ob = true
function loadOBJFile(objFile){
/* material of OBJ model */
var OBJMaterial = new THREE.MeshPhongMaterial({color: 0x8888ff});
var loader = new THREE.OBJLoader();
loader.load(objFile, function (object){
object.traverse (function (child){
if (child instanceof THREE.Mesh) {
child.material = OBJMaterial;
}
});
object.position.y = 0.1;
// add this code
object.is_ob = true;
scene.add(object);
});
}
function addEntity(object) {
loadOBJFile(object.name);
}
And then then you delete your object try this code:
function removeEntity(object){
var obj, i;
for ( i = scene.children.length - 1; i >= 0 ; i -- ) {
obj = scene.children[ i ];
if ( obj.is_ob) {
scene.remove(obj);
}
}
}
Try that and tell me if that works, it seems that three js doesn't recognize the object after added to the scene. But with this trick it works.
You can use this
function removeEntity(object) {
var scene = document.querySelectorAll("scene"); //clear the objects from the scene
for (var i = 0; i < scene.length; i++) { //loop through to get all object in the scene
var scene =document.getElementById("scene");
scene.removeChild(scene.childNodes[0]); //remove all specified objects
}

Dynamically Auto-Linking instance variables to object functions in javascript / jquery?

I'm trying to create a robust audio player in javascript (& jQuery). I know that there are other players out there, but I'd like to try creating my own (so please don't refer me to jquery plugins). This is essentially what I would like to do:
Main.js:
var player = new Player(AudioObj); // Audio object links to Audio class (not shown)
player.buttons.play = $('play');
player.buttons.pause = $('pause'); // Play and pause ID's link to HTML Document Element
Player.js:
Player = function(Audio) {
this.Audio = Audio;
this.buttons = {};
for(var button in this.buttons) {
button.live('click', this.button); // This is the line I Have NO idea about..
}
}
Player.prototype = {
play : function() {
// Do Something
},
pause : function() {
// Do something
}
}
So essentially, I would like the properties to be pre-linked to object functions when you initialize the Player, and to just have it work when I link it to an HTML element.
Thanks!
Matt Mueller
I think this would be a more OO way to go. Setup two more functions inside Player. One function would register a UI element to a Player action and another to unregister the action. So rather than keeping an explicit button collection you can just lean on jQuery.live and jQuery.die. For example:
function registerAction(selector, action) {
// you could have some logic to map the passed in action
// to the actual function name
$(selector).live('click', action/functionName);
}
function unRegisterAction(selector, [action]) {
// you could have some logic to map the passed in action
// to the actual function name
$(selector).die('click', [action/functionName]);
}
Then, your main.js example from above would become:
var player = new Player(AudioObj); // Audio object links to Audio class (not shown)
player.registerAction('#play', play);
player.registerAction('#pause', pause); // Play and pause ID's link to HTML Document Element
And your Player constructor would become:
Player = function(Audio) {
this.Audio = Audio;
}
Or something like that.
This is not the perfect solution but I find it to be pretty elegant:
Player.js
Player.prototype = {
init: function() {
var Player = this;
// Attach buttons to respected functions
for(var button in this.buttons) {
if(typeof Player[button] === "function")
$(this.buttons[button]).bind('click', {Player : this}, Player[button]);
}
},
play: function(e){
var Player = e.data.Player;
var Audio = Player.Audio;
Audio.play();
},
pause: function(e){
var Player = e.data.Player;
var Audio = Player.Audio;
Audio.pause();
}
}
Main.js
var audio = new AudioCore("UpToYou.mp3");
var player = new Player(audio);
player.buttons.play = $('#play');
player.buttons.pause = $('#pause');
player.init();
This provides a nice way to link buttons to the function without passing in a huge array or providing a bunch of options. I would be VERY happy to have a solution that would NOT require you to call init().

Categories