I have here codes that scramble declared words based on this video.Below are the codes that depends on array of words I declared on Unity Editor. The problem is I want it to be dynamic, like it will fetch words into database. I wrote a code in php that retrieves data from db and a code on csharp that reads the php via WWW method. I can't merge this two process- scramble words and getting words from db, Please help me guys, Thank you.
this is my Unity setup for scramble word. as you can see I attached WordScrambe.cs to Core Gameobject and declared 2 words-"YES" and "YOURS".
CharObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CharObject : MonoBehaviour {
public char character;
public Text text;
public Image image;
public RectTransform rectTransform;
public int index;
[Header("Appearance")]
public Color normalColor;
public Color selectedColor;
bool isSelected= false;
public CharObject Init(char c)
{
character = c;
text.text = c.ToString ();
gameObject.SetActive (true);
return this;
}
public void Select()
{
isSelected = !isSelected;
image.color = isSelected ? selectedColor : normalColor;
if (isSelected) {
WordScramble.main.Select (this);
} else {
WordScramble.main.UnSelect();
}
}
}
WordScramble.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Word
{
public string word;
[Header("leave empty if you want randomized")]
public string desiredRandom;
public string GetString()
{
if (!string.IsNullOrEmpty (desiredRandom))
{
return desiredRandom;
}
string result = word;
while (result==word)
{
result = "";
List<char> characters = new List<char> (word.ToCharArray ());
while (characters.Count > 0)
{
int indexChar = Random.Range (0, characters.Count - 1);
//Debug.Log(characters[indexChar]);
result += characters [indexChar];
Debug.Log(word);
characters.RemoveAt (indexChar);
}
}
return result;
}// end of Getstring Method
}
public class WordScramble : MonoBehaviour {
public Word[] words;
[Header("UI REFERENCE")]
public CharObject prefab;
public Transform container;
public float space;
public float lerpSpeed=5;
List<CharObject> charobjects = new List<CharObject>();
CharObject firstSelected;
public int currentWord;
public static WordScramble main;
void Awake()
{
main = this;
}
// Use this for initialization
void Start () {
ShowScramble (currentWord);
}
// Update is called once per frame
void Update ()
{
RepositionObject ();
}
void RepositionObject()
{
if (charobjects.Count==0) {
return;
}
float center = (charobjects.Count -1) / 2;
for (int i = 0; i < charobjects.Count; i++)
{
charobjects[i].rectTransform.anchoredPosition= Vector2.Lerp(charobjects[i].rectTransform.anchoredPosition, new Vector2((i- center)* space, 0), lerpSpeed* Time.deltaTime) ;
charobjects [i].index = i;
}
}
//show a random word to the screen
public void ShowScramble()
{
ShowScramble (Random.Range (0, words.Length - 1));
}
//<summary>Show word from collection with desired index
public void ShowScramble(int index)
{
charobjects.Clear ();
foreach (Transform child in container) {
Destroy (child.gameObject);
}
//Words Finished
if (index > words.Length - 1) {
Debug.LogError ("index out of range, please enter range betwen 0-" + (words.Length - 1).ToString ());
return;
}
char[] chars = words [index].GetString ().ToCharArray ();
foreach (char c in chars)
{
CharObject clone = Instantiate (prefab.gameObject).GetComponent<CharObject> ();
clone.transform.SetParent (container);
charobjects.Add (clone.Init (c));
}
currentWord = index;
}
public void Swap(int indexA, int indexB)
{
CharObject tmpA = charobjects [indexA];
charobjects[indexA] = charobjects [indexB];
charobjects[indexB] = tmpA;
charobjects [indexA].transform.SetAsLastSibling ();
charobjects [indexB].transform.SetAsLastSibling ();
CheckWord ();
}
public void Select(CharObject charObject)
{
if (firstSelected)
{
Swap (firstSelected.index, charObject.index);
//Unselect
firstSelected.Select();
charObject.Select();
} else {
firstSelected = charObject;
}
}
public void UnSelect()
{
firstSelected = null;
}
public void CheckWord()
{
StartCoroutine (CoCheckWord());
}
IEnumerator CoCheckWord()
{
yield return new WaitForSeconds (0.5f);
string word = "";
foreach (CharObject charObject in charobjects)
{
word += charObject.character;
}
if (word == words [currentWord].word) {
currentWord++;
ShowScramble (currentWord);
}
}
}
Below are the codes for retrieving data from db using PHP and passing data to unity.
read.php
<?php
include '../../connection.php';
$query=mysqli_query($conn, "SELECT * FROM words");
while($fetch=mysqli_fetch_array($query)){
echo $get=$fetch["words"];
echo ",";
}
?>
fetch.cs-I attached this to Main Camera on Unity Editor for the mean time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class fetch : MonoBehaviour {
public string[] dbWords;
IEnumerator Start(){
WWW words=new WWW("http://localhost/bootstrap/android/v2/read.php");
yield return words;
string wordsDataString=words.text;
print(wordsDataString);
dbWords=wordsDataString.Split(',');
}
}
In short I want to make a scramble game in unity that the words of it depends on the database . I have the process of word scramble(but static) and retrieving data from database but not connected to scramble game I made, means my project is not yet dynamic, I'm sorry for uncleared explanations.
Thank you and more power! :)
Welcome to SO!
It is not entirely clear where your problem lies, however I think you mean to say that you are not receiving a result from your database?
Let's start by moving your Database logic to a separate class for good practice.
Also the Start Method of a MonoBehaviour is of returntype void, and not an IENumerator. You need an IENumerator, which you can call with StartCoroutine.
Create a seperate class like below
public static class NetworkManager
{
public static IEnumerator Fetch(Action<string[]> callback)
{
WWW words=new WWW("http://localhost/bootstrap/android/v2/read.php");
yield return words;
string wordsDataString=words.text;
print(wordsDataString);
var result = wordsDataString.Split(',');
callback?.Invoke(result);
}
}
I cannot test your code that you had in your Fetch method because you are using it locally, but let's assume it works for now.
Notice the callback as a parameter.
This allows you to register an action that will fire once your database call is completed.
It is invoked in the last line of the method.
You can then call the method like this:
public class SomeClass : MonoBehaviour
{
StartCoroutine(NetworkManager.Fetch( (words) =>
{
// Do something with the words!
SomeMethod(words);
});
}
As soon as the Coroutine finishes, any code between the brackets is executed. In this case "SomeMethod" accepting words as a parameter will fire.
I hope this clarifies and answers your question!
Related
I want to create public Scene[] levels; and manually assign my levels to the array, then loop through it and generate level selection buttons, but it won't show up in the inspector.
Is there any workaround?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class True : MonoBehaviour
{
// Start is called before the first frame update
public static int money;
[SerializeField]
public SceneManager[] scenes;
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void nextscencefirst()
{
SceneManager.LoadScene("Level2");
money++;
}
}
SceneManager is a built-in static class to control scenes during runtime. We can go to any scene by calling LoadScene method from that class. Also SceneManager cannot be seen in Inspector since it cannot be serialized class.
A reminder: Your scenes should be listed on build settings for these to work.
There are three ways to do what you want to do:
Method 1. Create a string list that holds names of scenes
public List<string> sceneNameList = new List<string>;
Method 2. Create a list of indices of scenes that added in build settings.
public List<int> sceneBuildIndexList = new List<int>
If the names of scenes are long or somehow difficult or you want to use sceneBuildIndex value it would be good to create a class and reach scenes from it
[System.Serializable]
public class SceneData
{
public int sceneBuildIndex;
public string sceneKey;
//public void LoadScene() //Maybe
}
public List<SceneData> sceneDataList = new List<SceneData>();
public SceneData GetSceneData(string key)
{
for (int i = 0; i < sceneDataList.Count; i++)
{
if (sceneDataList[i].sceneKey == key)
{
return sceneDataList[i];
}
}
return null;
}
Method 3: In Unity most classes are created from UnityEngine.Object, so it may let you assign scene from the Inspector.
[System.Serializable]
public class SceneData
{
public UnityEngine.Object scene;
public string key;
public void LoadScene()
{
if (scene == null)
{
Debug.LogError("Scene is not assigned");
return;
}
string pathToScene = AssetDatabase.GetAssetPath(scene);
SceneManager.LoadScene(pathToScene); //If the scene is not set in BuildSettings it will throw an error.
}
}
public List<SceneData> sceneDataList = new List<SceneData>();
public SceneData GetSceneData(string key)
{
for (int i = 0; i < sceneDataList.Count; i++)
{
if (sceneDataList[i].key == key)
{
return sceneDataList[i];
}
}
return null;
}
private void Awake()
{
SceneData data = GetSceneData("Level1");
if (data != null)
{
data.LoadScene();
}
}
There might be similar questions to this one but I couldn't find any useful.
I have a simple scrips which has a list of classes that contains audio clips, id, and event system individually for each one of those elements.
I need to make that audio clip fields to list and make them play by order until the last one then stop and fire event.
Here's my code for only one audio clip slot:
(Also i tried audio clip array but its just playing the first one on the audio clip array)
public class MainAudioManager : MonoBehaviour {
public List<soundInfo> currentsoundinfoList = new List<soundInfo>();
AudioSource audioSource;
soundInfo curentSoundInfo;
float audioLenght;
void Start () {
audioSource = gameObject.GetComponent<AudioSource> ();
}
public void SetAudioToPlay (int ID) {
for (int i = 0; i < currentsoundinfoList.Count; i++) {
if (currentsoundinfoList [i].ID == ID) {
curentSoundInfo = currentsoundinfoList[i];
audioSource.clip = curentSoundInfo.clipToPlay;
audioSource.Play ();
audioLenght = audioSource.clip.length;
StartCoroutine ("waitnigTillEbd");
return;
}
}
}
IEnumerator waitnigTillEbd () {
yield return new WaitForSeconds (audioLenght + 1f);
curentSoundInfo.eventOnSound.Invoke ();
}
[System.Serializable]
public class soundInfo {
public string name;
public int ID;
public AudioClip clipToPlay;
public UnityEvent eventOnSound;
}
}
alright i found the solution by my self. here is the final result for creating list of sound with event onstop attached to each one of them individually and also playable by ID from another event and classes ,for anyone who need it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
[RequireComponent(typeof(AudioSource))]
public class MainAudioManager : MonoBehaviour {
public List<soundInfo> soundList = new List<soundInfo>();
AudioSource audioSource;
soundInfo curentSoundInfo;
float audioLenght;
void Start () {
audioSource = gameObject.GetComponent<AudioSource> ();
}
public void SetAudioToPlay (int ID) {
for (int i = 0; i < soundList.Count; i++) {
if (soundList [i].ID == ID) {
curentSoundInfo = soundList [i];
StartCoroutine(playSequencely());
return;
}
}
}
IEnumerator playSequencely () {
yield return null;
for (int cnt = 0; cnt < curentSoundInfo.clipsToPlay.Length; cnt++) {
audioSource.clip = curentSoundInfo.clipsToPlay [cnt];
audioSource.Play ();
while (audioSource.isPlaying) {
yield return null;
}
}
//Debug.Log ("Last Audio Is Playing");
curentSoundInfo.onStop.Invoke ();
}
}
[System.Serializable]
public class soundInfo {
public string name;
public int ID;
[TextArea (2, 8)] public string About;
public AudioClip[] clipsToPlay;
//public float delayBetween;
public UnityEvent onStop;
}
I have a currency script for my game that is not displaying how much money the user has.
It was working before I added the PlayerPrefs class.
But after the addition, it will not display anything.
FYI, the PlayerPrefs class allows me to display numbers across multiple scenes in Unity.
I have posted my code below
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class squidCoin : MonoBehaviour {
public Text coinDisplay;
public int addMoneyAmmount;
public int squidCoins;
public float saveInterval;
public float paycheckTime;
// Use this for initialization
void Start () {
squidCoins = 50;
PlayerPrefs.SetInt("SquidCoins", squidCoins);
StartCoroutine(moneyADD());
StartCoroutine("SaveMoney");
}
public void squidCoinPayCheck(int squidCoinsToAdd){
squidCoins += squidCoinsToAdd;
}
public void Awake(){
PlayerPrefs.GetInt("SquidCoinsSaves");
}
public void minusSquidCoin(int squidCoinsToSubtract){
if(squidCoins - squidCoinsToSubtract < 0){
Debug.Log ("Oops Hes Broke");
squidCoins += addMoneyAmmount;
}
else{
squidCoins -= squidCoinsToSubtract;
}
}
IEnumerator moneyADD(){
yield return new WaitForSeconds(paycheckTime);
squidCoins += addMoneyAmmount;
}
IEnumerator SaveMoney (){
while (true)
{
yield return new WaitForSeconds(saveInterval);
PlayerPrefs.SetInt("SquidCoinSaves", squidCoins);
}
}
// Update is called once per frame
void Update () {
coinDisplay.text = "You Have: " + PlayerPrefs.GetInt("SquidCoinsSaves");
}
}
i looked at all of your code and it seems there is have many wrong details. I just fixed it and noted your wrongs with comment in front of the wrong parts
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class squidCoin : MonoBehaviour {
public Text coinDisplay;
public int addMoneyAmmount;
public int squidCoins;
public float saveInterval;
public float paycheckTime;
// Use this for initialization
void Start () {
squidCoins = 50;
PlayerPrefs.SetInt("SquidCoinsSaves", squidCoins); //your string name was wrong
StartCoroutine(moneyADD());
StartCoroutine("SaveMoney");
}
public void squidCoinPayCheck(int squidCoinsToAdd){
squidCoins += squidCoinsToAdd;
}
public void Awake(){
//PlayerPrefs.GetInt("SquidCoinsSaves"); //you can not get it like this, first you must equal this ti intiger type varible
}
public void minusSquidCoin(int squidCoinsToSubtract){
if(squidCoins - squidCoinsToSubtract < 0){
Debug.Log ("Oops Hes Broke");
squidCoins += addMoneyAmmount;
}
else{
squidCoins -= squidCoinsToSubtract;
}
}
IEnumerator moneyADD(){
yield return new WaitForSeconds(paycheckTime);
squidCoins += addMoneyAmmount;
}
IEnumerator SaveMoney (){
while (true)
{
yield return new WaitForSeconds(saveInterval);
PlayerPrefs.SetInt("SquidCoinsSaves", squidCoins); //string name was wrong
}
}
// Update is called once per frame
void Update () {
coinDisplay.text = "You Have: " + PlayerPrefs.GetInt("SquidCoinsSaves");
}
}
I have four buttons using the same prefab and holding 4 text elements from an array out of which only one is assigned bool value to true. I am trying to access that true element when any of false element is clicked. i want to highlight true element when the false element is clicked. can anyone please help me to achieve this functionality?
using simpleobjectpool
taking reference from unity quiz game tutorial
Thanks
Answer Button Script
public class AnswerButton : MonoBehaviour
{
public Text answerText;
private AnswerData answerData;
private GameController gameController;
private bool isCorrect;
void Start()
{
gameController = FindObjectOfType<GameController>();
}
public void Setup(AnswerData data)
{
answerData = data;
answerText.text = answerData.answerText;
}
public void HandleClick()
{
gameController.AnswerButtonClicked(answerData.isCorrect);
{
if (answerData.isCorrect)
{
}
if (!answerData.isCorrect)
{
}
}
Answer Data Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class AnswerData
{
public string answerText;
public bool isCorrect;
}
QuestionData Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class QuestionData
{
public string questionText;
public AnswerData[] answers;
}
Game Controller Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;
public class GameController : MonoBehaviour
{
public Text questionText;
public Text scoreDisplayText;
public SimpleObjectPool answerButtonObjectPool;
public Transform answerButtonParent;
public GameObject questionPanel;
public GameObject roundOverPanel;
public GameObject levelsPanel;
private DataController dataController;
private RoundData currentRoundData;
private bool isRoundActive;
private float timeBeetweenQuestions = 3.0f;
private List<GameObject> answerButtonGameObjects = new List<GameObject>();
private QuestionData[] questionPool;
private int questionIndex;
private int qNumber = 0;
private List<int> questionIndexesChosen = new List<int>();
public int playerScore = 0;
public int totalQuestions;
private static int pointAddedForCorrectAnswer;
public AudioSource answerButtonClicked;
public AudioSource wrongAnswerClicked;
void Start ()
{
dataController = FindObjectOfType<DataController>();
currentRoundData = dataController.GetCurrentRoundData();
questionPool = currentRoundData.questions;
playerScore = 0;
questionIndex = 0;
scoreDisplayText.text = "Score: " + playerScore.ToString();
isRoundActive = true;
ShowQuestion();
}
private void ShowQuestion()
{
RemoveAnswerButtons();
QuestionData questionData = questionPool[questionIndex];
questionText.text = questionData.questionText;
for (int i = 0; i < questionData.answers.Length; i++)
{
GameObject answerButtonGameObject =
answerButtonObjectPool.GetObject();
answerButtonGameObjects.Add(answerButtonGameObject);
answerButtonGameObject.transform.SetParent(answerButtonParent);
AnswerButton answerButton =
answerButtonGameObject.GetComponent<AnswerButton>();
AnswerButton.Setup(questionData.answers[i]);
}
}
private void RemoveAnswerButtons()
{
while (answerButtonGameObjects.Count > 0)
{
answerButtonObjectPool.ReturnObject(answerButtonGameObjects[0]);
answerButtonGameObjects.RemoveAt(0);
}
}
IEnumerator TransitionToNextQuestion()
{
yield return new WaitForSeconds(timeBeetweenQuestions);
ShowQuestion();
}
IEnumerator WaitForFewSeconds()
{
yield return new WaitForSeconds(timeBeetweenQuestions);
EndRound();
}
IEnumerator ReturnCorrectButtonColor()
{
Debug.Log("im correct");
GetComponent<Button>().image.color = Color.green;
yield return new WaitForSeconds(seconds: 2.9f);
GetComponent<Button>().image.color = Color.white;
}
IEnumerator ReturnWrongButtonColor()
{
Debug.Log("im wrong");
GetComponent<Button>().image.color = Color.red;
yield return new WaitForSeconds(seconds: 2.9f);
GetComponent<Button>().image.color = Color.white;
}
public void AnswerButtonClicked (bool isCorrect)
{
if (isCorrect)
{
playerScore += currentRoundData.pointAddedForCorrectAnswer;
scoreDisplayText.text = "Score: " + playerScore.ToString();
//play coorect answer sound
answerButtonClicked.Play();
StartCoroutine(ReturnCorrectButtonColor());
}
if (!isCorrect)
{
//play wrong answer sound
answerButtonClicked = wrongAnswerClicked;
answerButtonClicked.Play();
StartCoroutine(ReturnWrongButtonColor());
// buttons = GameObject.FindGameObjectsWithTag("Answer");
// {
// foreach (GameObject button in buttons)
// {
// if (button.GetComponent<AnswerButton>
//().answerData.isCorrect)
// {
// button.GetComponent<AnswerButton>
// ().StartCoroutine(ReturnCorrectButtonColor());
// }
// }
//}
}
if (qNumber < questionPool.Length - 1) /
{
qNumber++;
StartCoroutine(TransitionToNextQuestion());
}
else
{
StartCoroutine(WaitForFewSeconds());
}
}
public void EndRound()
{
isRoundActive = false;
questionPanel.SetActive(false);
roundOverPanel.SetActive(true);
}
//on button click return to main menu
public void ReturnToMenu ()
{
SceneManager.LoadScene("MenuScreen");
}
}
In order to highlight both Wrong (the clicked one) and the Right buttons you need to have access to both buttons. This means that you can't do highlighting from HandleClick method of your Answer Button Script, as it only has access to itself, e.g. to the Wrong button.
The good thing is that this method notifies GameController that the button has been clicked. GameController knows about all the buttons, so it can easily highlight both buttons.
So, instead of launching your highlight subroutines from Answer Button's HandleClick, you should do this from GameController's AnswerButtonClicked: identify both the Right button and the clicked button there and launch appropriate subroutines for them.
Update:
For instance, your ReturnCorrectButtonColor would look like:
IEnumerator ReturnCorrectButtonColor( GameObject button )
{
Debug.Log("im correct");
button.GetComponent<Button>().image.color = Color.green;
yield return new WaitForSeconds(seconds: 2.9f);
button.GetComponent<Button>().image.color = Color.white;
}
so in AnswerButtonClicked you identify which button to highlight as a correct answer button and pass it as a paramter to this method:
StartCoroutine(ReturnCorrectButtonColor(correctButton));
I have three characters and each of them has a camera attached to them.By default they are disabled but one.I made a character selector which is supposed to change them.I have a problem where I can move the selected one but the camera stays at the last one.
Here is the script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityStandardAssets.Utility;
public class GameManageer : MonoBehaviour {
public Camera[] cams = new Camera[3];
public Character CurrentCharacter;
public List<Character> Characters = new List<Character>();
public List<Item> AllItems;
bool ShowCharWheel;
public int SelectedCharacter;
public int lastCharacter;
public static GameManageer Instance;
void Awake(){
Instance = this;
foreach (Character c in Characters){
c.Instance = Instantiate(c.PlayerPrefab, c.HomeSpawn.position, c.HomeSpawn.rotation) as GameObject;
c.Instance.GetComponent<PlayerController>().LocalCharacter = c;
}
ChangeCharacter(Characters[PlayerPrefs.GetInt("SelectedChar")]);
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.C)) {
ShowCharWheel = true;
} else {
ShowCharWheel = false;
}
}
void ChangeCharacter(Character c){
lastCharacter = SelectedCharacter;
SelectedCharacter = Characters.IndexOf (c);
cams [SelectedCharacter].gameObject.SetActive (true);
cams [lastCharacter].gameObject.SetActive (false);
CurrentCharacter = c;
Characters [lastCharacter].Instance.GetComponent<PlayerController> ().CanPlay = false;
Characters [SelectedCharacter].Instance.GetComponent<PlayerController> ().CanPlay = true;
PlayerPrefs.SetInt ("SelectedChar", SelectedCharacter);
}
void OnGUI(){
if (ShowCharWheel) {
GUILayout.BeginArea(new Rect(Screen.width - 64, Screen.height - 192,64,192));
foreach (Character c in Characters){
if (GUILayout.Button(c.Icon,GUILayout.Width(64),GUILayout.Height(64))){
ChangeCharacter(c);
}
}
GUILayout.EndArea();
}
}
}
[System.Serializable]
public class Character {
public string Name;
public Texture2D Icon;
public GameObject PlayerPrefab;
public GameObject Instance;
public Transform HomeSpawn;
}
[System.Serializable]
public class Item{
public string Name;
public Texture2D Icon;
public ItemInstance InstancePrefab;
}
This should do the job:
cams[SelectedCharacter].enabled = true;
cams[lastCharacter].enabled = false;
Use Depth:
foreach (Camera cam in cams)
{
cam.depth = cam == cams[SelectedCharacter] ? 10 : 0;
}
I think the real problem here though, is that you have more cameras in the scene which you have to manage as well, other then only the last and current selected character... in which case:
foreach (Camera cam in cams)
{
cam.SetActive(cam == cams[SelectedCharacter]);
}