Simple question but make me blur.
I have an audio source on let say "Main" scene, and I make it DontDestroyOnLoad, which make it could keep playing my audio even i going next scene, let say "Game" scene.
Problem is, when i get back from "Game" scene to "Main" scene, my audio will restart over but not continue playing as i expected. How should i actually script for this?
My current script :
void Awake() {
if (instance != null && instance != this) {
Destroy(this.gameObject);
return;
} else {
instance = this;
}
DontDestroyOnLoad(this.gameObject);
}
Simply Instantiate you AudioController object if there is no AudioController in the main scene.
void Start()
{
if(GameObject.FindWithTag("AudioController") == NULL)
{
Instantiate(AudioController);
}
}
AudioController is the one that will have DontDestroyOnLoad and AudioSource in it. This way there will be just one instance.
Related
I'm trying to make an Ouch! sound play at only the start of an overlap between a ball and wall Actors. So if the overlap is maintained I don't want the sound to play unless actors stop overlapping and then overlap again.
Here is part of the code where I'm trying to play the ouch sound:
for (BaseActor wallActor : BaseActor.getList(mainStage, "com.mygdx.game.WallBlock")){
ball.preventOverlap(wallActor);
ouch.play();
}
Please provide an example of how I could make this work.
You didn't posted much code but the solution is simple, keep a boolean overlapping in your ball actor and only when it changes from false to true play the sound.
Pseudocode:
public class Ball
{
private boolean overlapping;
private YourGame game; //could be a screen too or simply a world object
// other ball fields ...
public void update()
{
boolean wasOverlapping = overlapping;
overlapping = isOverlapping();
if(!wasOverlapping && overlapping)
ouch.play();
if(!overlapping && wasOverlapping)
{
//you could also play a sound when it stops overlapping here!
}
}
private boolean isOverlapping()
{
for(Wall wall : game.getWalls())
{
if(wall.overlap(this)) //this refers to the ball
return true;
}
return false;
}
}
I am made a door script and it works fine but now i want to add different sounds when the door opens and when it closes. I added an Audio Source at the door and added the doorOpen sound. How can i add a doorClose sound too and make it play via the script?
Audio Source
if (open) {
GetComponent<AudioSource>().Play ();
} else {
GetComponent<AudioSource>().Play ();
}
Check Audio & Sound Tutorial. Here is sample code:
using UnityEngine;
using System.Collections;
namespace Completed
{
public class SoundManager : MonoBehaviour
{
public AudioSource efxSource; //Drag a reference to the audio source which will play the sound effects.
public AudioSource musicSource; //Drag a reference to the audio source which will play the music.
public static SoundManager instance = null; //Allows other scripts to call functions from SoundManager.
public float lowPitchRange = .95f; //The lowest a sound effect will be randomly pitched.
public float highPitchRange = 1.05f; //The highest a sound effect will be randomly pitched.
void Awake ()
{
//Check if there is already an instance of SoundManager
if (instance == null)
//if not, set it to this.
instance = this;
//If instance already exists:
else if (instance != this)
//Destroy this, this enforces our singleton pattern so there can only be one instance of SoundManager.
Destroy (gameObject);
//Set SoundManager to DontDestroyOnLoad so that it won't be destroyed when reloading our scene.
DontDestroyOnLoad (gameObject);
}
//Used to play single sound clips.
public void PlaySingle(AudioClip clip)
{
//Set the clip of our efxSource audio source to the clip passed in as a parameter.
efxSource.clip = clip;
//Play the clip.
efxSource.Play ();
}
//RandomizeSfx chooses randomly between various audio clips and slightly changes their pitch.
public void RandomizeSfx (params AudioClip[] clips)
{
//Generate a random number between 0 and the length of our array of clips passed in.
int randomIndex = Random.Range(0, clips.Length);
Keep reference to both the Audio files.
Then,
if (open) {
GetComponent<AudioSource> ().clip = _OpenClip;
GetComponent<AudioSource> ().Play ();
} else {
GetComponent<AudioSource> ().clip = _CloseClip;
GetComponent<AudioSource> ().Play ();
}
I am extinguishing fire particles by smoke particles so then I want to check that object is destroyed or not, if object is destroyed then load new scene.
Here is my script,,,,,, Any suggestions ?
using UnityEngine;
using System.Collections;
public class hey : MonoBehaviour {
void Start(){
GetComponent<ParticleSystem> ().emissionRate = 0;
}
void Update(){
if (Input.GetMouseButtonDown (1)) {
GetComponent<ParticleSystem> ().Emit (20);
}
}
void OnParticleCollision(GameObject obj)
{
Destroy (obj, 2.0f);
//here i want to check and then load new scene..
//I try that thing, but failed..nothing happen
if (object.Equals (obj, null)) {
Application.LoadLevel (7);
}
//also this one, but nothing happens
if(gameObject.tag=="fire123"==null){
Application.LoadLevel (7);
}
// also this one too, but failed :-(
void OnDestroy(){
Application.LoadLevel (7); } }
The problem: Destroy(obj, **2.0f**);
Because of the delay the item is not destroyed when the if is evaluated.
So either don't use a delay or make OnParticleCollision a coroutine and use a yield return new waitForSeconds or put the check somewhere else like Update or use OnDestroy in a script on the particle that gets destroyed.
I'm making a simple 2D game for Android using the Unity3D game engine. I created all the levels and everything but I'm stuck at making the game over/retry menu. So far I've been using new scenes as a game over menu. I used this simple script:
#pragma strict
var level = Application.LoadLevel;
function OnCollisionEnter(Collision : Collision)
{
if(Collision.collider.tag == "Player")
{
Application.LoadLevel("GameOver");
}
}
And this as a 'menu':
#pragma strict
var myGUISkin : GUISkin;
var btnTexture : Texture;
function OnGUI() {
GUI.skin = myGUISkin;
if (GUI.Button(Rect(Screen.width/2-60,Screen.height/2+30,100,40),"Retry"))
Application.LoadLevel("Easy1");
if (GUI.Button(Rect(Screen.width/2-90,Screen.height/2+100,170,40),"Main Menu"))
Application.LoadLevel("MainMenu");
}
The problem stands at the part where I have to create over 200 game over scenes, obstacles (the objects that kill the player) and recreate the same script over 200 times for each level. Is there any other way to make this faster and less painful?
Edit : If possible,please when you suggest your ideas,use javascript only,I don't understand C#,not even a little bit.I know Im asking too much but it realy confuses me.
Thank you.
There are several different solutions, but I would recommend using PlayerPrefs. This has the extra benefit of persisting even when the application is closed and then re-opened.
In your Awake() function of your Main Menu class, you can get the current level and store it in a static string of your Main Menu class. If it is the player's 1st time, use the name for level 1.
Something like this:
static string currentLevelName;
void Awake()
{
currentLevelName = PlayerPrefs.GetString("CurrentLevel");
if (currentLevelName == defaultValue)
{
currentLevelName = "Level1"
}
}
Then, modify your button to do this instead:
if (GUI.Button(Rect(Screen.width/2-60,Screen.height/2+30,100,40),"Retry"))
Application.LoadLevel(currentLevelName);
Whenever the player advances to the next level, set the string in PlayerPrefs to the new level name:
PlayerPrefs.SetString("CurrentLevel", Application.loadedLevelName);
You can create a class with static properties. For example (in c#)
public class GameOverInput
{
public static string name;
public static string retryLevel;
//all the info you need
}
Then you can easily read the input in your game over scene (only one is needed)
public class GameOverMenu : MonoBehavior
{
void Start()
{
Debug.Log("You were killed by " + GameOverInput.name);
Application.LoadLevel(GameOverInput.retryLevel);
}
}
And you set this info just before loading the game over scene
if (Collision.collider.tag == "Player")
{
GameOverInput.name = "Baddie";
Application.LoadLevel("GameOver");
}
Another option would be to make something like a singleton LevelManager MonoBehavior and add it to an object named "Level Manager". Use the DontDestroyOnLoad function to make the object persist even when you load another level.
class LevelManager : MonoBehavior
{
static LevelManager _instance;
public string currentLevelName;
public string killedBy;
function Awake ()
{
if (_instance == null)
{
_instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject); // Make sure we never have more than 1 Level Manager.
}
}
LevelManager Instance
{
get
{
if (_instance == null)
{
GameObject levelManagerObject = GameObject.Find("Level Manager");
_instance = levelManagerObject.GetComponent<LevelManager>();
}
return _instance
}
}
}
Then, from the main menu class, you can always access the Level Manager like so:
Debug.Log("Killed by " + LevelManager.Instance.killedBy);
or
LevelManager.Instance.currentLevelName = Application.loadedLevelName;
class MyCanvas extends Canvas{
protected void paint(Graphics g) {
//Process keyboard
//Update movement/position
//Draw
repaint(); //loop
}
}
Until now I used the Canvas's paint() for the game loop, but I came across some article in the web that says that another thread should be used here
Now I'm wondering if paint() is a good/safe place to process all the data.
So can I continue doing it like this?
Or should I make another thread for that?
I'm not sure of pros and cones of each so I'm not sure which method to choose but I got used to repaint method
I would not use paint() that way, no. paint() should be for painting ... drawing. I would split your monitoring of user input, and game logic processing, outside that method.
Have you considered using the GameCanvas subclass of Canvas?
It gives you some nice double-buffering features. You would create another thread, which would call your GameCanvas' run() method, where it would check for user input, update the game logic, then draw to the off-screen buffer, and finally trigger repainting of the on-screen buffer.
Something like this:
class MyGameCanvas extends GameCanvas implements Runnable {
/** start this game! */
public void start() {
Thread worker = new Thread(this);
worker.start();
}
/** run the game loop */
public void run() {
// Get the Graphics object for the off-screen buffer
Graphics g = getGraphics();
while (true) {
// Check user input and update positions if necessary
int keyState = getKeyStates();
if ((keyState & LEFT_PRESSED) != 0) {
sprite.move(-1, 0);
}
else if ((keyState & RIGHT_PRESSED) != 0) {
sprite.move(1, 0);
}
// Clear the background to white
g.setColor(0xFFFFFF);
g.fillRect(0,0,getWidth(), getHeight());
// Draw the Sprite
sprite.paint(g);
// Flush the off-screen buffer
flushGraphics();
try {
// TODO: of course, you might want a more intelligent
// sleep interval, that reflects the amount of time
// remaining (if any) in the cycle ...
Thread.sleep(10); //sleep 10 ms
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Note that I put basically everything in the run() method, for brevity. I'm assuming your game is more complicated, and would warrant splitting off separate methods for getting user input, updating logic, and then calling graphics/paint methods. Those would all be called from run().
Usage
Start this in your MIDlet's startApp() method:
MyGameCanvas gameCanvas = new MyGameCanvas();
gameCanvas.start();
exitCommand = new Command("Exit", Command.EXIT, 1);
gameCanvas.addCommand(exitCommand);
gameCanvas.setCommandListener(this);
Display.getDisplay(this).setCurrent(gameCanvas);
References
http://www.codeproject.com/Articles/35833/Programming-2D-Games-in-J2ME
an example that shows a better implementation, if you don't use GameCanvas and just use Canvas.
PowerPoint overview of Game APIs and looping , with code and general theory