I have completed a tutorial on how to make a memory card, everything works great, I can play the game and match all the cards (20 or 30 or 40 for different categories cause I have 6 of them) and I added a timer. I can even reset the game and start all over, and all the cards are randomly sorted out.
But I want to go beyond the tutorial and put some sound effects in the game to make it more fun. I get that you can play sounds on mouse clicks and stuff, but I want to play sounds when specific cards are revealed. Duck card appears and you hear a quacking sound or his name. I'm a beginner and I don't know how to add it.
I'm not sure if I would start a new C# script or add to my existing (PictureManager) script or (Picture) script.
Any help would be appreciated. Thank you. These are my (PictureManager) and (Picture) script for the game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PictureManager : MonoBehaviour
{
public Picture PicturePrefab;
public Transform PicSpawnPosition;
public Vector2 StartPosition = new Vector2(-2.15f, 3.62f);
public AudioSource WinSound;
public AudioSource BgSound;
[Space]
[Header("End Game Screen")]
public GameObject EndGamePanel;
public GameObject NewBestScoreText;
public GameObject YourScoreText;
public GameObject EndTimeText;
/*to rremove
public List<AudioClip> Vegetabels = new List<AudioClip>();
private AudioSource audioSource;
to remove*/
public enum GameState
{
NoAction,
MovingOnPositions,
DeletingPuzzles,
FlipBack,
Checking,
GameEnd
};
public enum PuzzleState
{
PuzzleRotating,
CanRotate,
};
public enum RevealedState
{
NoRevealed,
OneRevealed,
TwoRevealed
};
[HideInInspector]
public GameState CurrentGameState;
[HideInInspector]
public PuzzleState CurrentPuzzleState;
[HideInInspector]
public RevealedState PuzzleRevealedNumber;
[HideInInspector]
public List<Picture> PictureList;
private Vector2 _offset = new Vector2(1.42f, 1.52f);
private Vector2 _offsetFor15Pairs = new Vector2(1.08f, 1.22f);
private Vector2 _offsetFor20Pairs = new Vector2(1.08f, 1.0f);
private Vector3 _newScaleDown = new Vector3(0.9f, 0.9f, 0.001f);
private List<Material> _materialList = new List<Material>();
private List<string> _texturePathList = new List<string>();
private Material _firstMaterial;
private string _firstTexturePath;
private int _firstRevealedPic;
private int _secondRevealedPic;
private int _revealedPicNumber = 0;
private int _picToDestroy1;
private int _picToDestroy2;
private bool _corutineStarted = false;
private int _pairNumbers;
private int _removedPairs;
private Timer _gameTimer;
void Start()
{
//BgSound.Play();
CurrentGameState = GameState.NoAction;
CurrentPuzzleState = PuzzleState.CanRotate;
PuzzleRevealedNumber = RevealedState.NoRevealed;
_revealedPicNumber = 0;
_firstRevealedPic = -1;
_secondRevealedPic = -1;
_removedPairs = 0;
_pairNumbers = (int)GameSettings.Instance.GetPairNumber();
_gameTimer = GameObject.Find("Main Camera").GetComponent<Timer>();
LoadMaterials();
if(GameSettings.Instance.GetPairNumber()== GameSettings.EPairNumber.E10Pairs)
{
CurrentGameState = GameState.MovingOnPositions;
SpwanPictureMesh(4, 5, StartPosition, _offset, false);
MovePicture(4, 5, StartPosition, _offset);
}
else if (GameSettings.Instance.GetPairNumber() == GameSettings.EPairNumber.E15Pairs)
{
CurrentGameState = GameState.MovingOnPositions;
SpwanPictureMesh(5, 6, StartPosition, _offset, false);
MovePicture(5, 6, StartPosition, _offsetFor15Pairs);
}
else if (GameSettings.Instance.GetPairNumber() == GameSettings.EPairNumber.E20Pairs)
{
CurrentGameState = GameState.MovingOnPositions;
SpwanPictureMesh(5, 8, StartPosition, _offset, true);
MovePicture(5, 8, StartPosition, _offsetFor20Pairs);
}
}
public void CheckPicture()
{
CurrentGameState = GameState.Checking;
_revealedPicNumber = 0;
for(int id = 0; id < PictureList.Count; id++)
{
if(PictureList[id].Revealed && _revealedPicNumber < 2)
{
if(_revealedPicNumber == 0)
{
_firstRevealedPic = id;
_revealedPicNumber++;
//audioSource.PlayOneShot(Vegetabels[id]);
}
else if (_revealedPicNumber == 1)
{
_secondRevealedPic = id;
_revealedPicNumber++;
}
}
if (_revealedPicNumber == 2)
{
if (PictureList[_firstRevealedPic].GetIndex() == PictureList[_secondRevealedPic].GetIndex() && _firstRevealedPic != _secondRevealedPic)
{
CurrentGameState = GameState.DeletingPuzzles;
_picToDestroy1 = _firstRevealedPic;
_picToDestroy2 = _secondRevealedPic;
}
else
{
CurrentGameState = GameState.FlipBack;
}
}
}
CurrentPuzzleState = PictureManager.PuzzleState.CanRotate;
if(CurrentGameState == GameState.Checking)
{
CurrentGameState = GameState.NoAction;
}
}
private void DestroyPicture()
{
PuzzleRevealedNumber = RevealedState.NoRevealed;
PictureList[_picToDestroy1].Deactivate();
PictureList[_picToDestroy2].Deactivate();
_revealedPicNumber = 0;
_removedPairs++;
CurrentGameState = GameState.NoAction;
CurrentPuzzleState = PuzzleState.CanRotate;
}
private IEnumerator FlipBack()
{
_corutineStarted = true;
yield return new WaitForSeconds(0.5f);
PictureList[_firstRevealedPic].FlipBack();
PictureList[_secondRevealedPic].FlipBack();
PictureList[_firstRevealedPic].Revealed = false;
PictureList[_secondRevealedPic].Revealed = false;
PuzzleRevealedNumber = RevealedState.NoRevealed;
CurrentGameState = GameState.NoAction;
_corutineStarted = false;
}
private void LoadMaterials()
{
var materialFilePath = GameSettings.Instance.GetMaterialDirectoryName();
var textureFilePath = GameSettings.Instance.GetPuzzleCategoryTextureDirectoryName();
var pairNumber = (int)GameSettings.Instance.GetPairNumber();
const string matBaseName = "Pic";
var firstMaterialName = "Back";
for(var index = 1; index <= pairNumber; index++)
{
var currentFilePath = materialFilePath + matBaseName + index;
Material mat = Resources.Load(currentFilePath, typeof(Material)) as Material;
_materialList.Add(mat);
var currentTextureFilePath = textureFilePath + matBaseName + index;
_texturePathList.Add(currentTextureFilePath);
}
_firstTexturePath = textureFilePath + firstMaterialName;
_firstMaterial = Resources.Load(materialFilePath + firstMaterialName, typeof(Material)) as Material;
}
void Update()
{
if (PauseMenu.isPaused == false) {
if (CurrentGameState == GameState.DeletingPuzzles)
{
if(CurrentPuzzleState == PuzzleState.CanRotate)
{
DestroyPicture();
CheckGameEnd();
}
}
if (CurrentGameState == GameState.FlipBack)
{
if(CurrentPuzzleState == PuzzleState.CanRotate && _corutineStarted == false)
{
StartCoroutine(FlipBack());
}
}
if(CurrentGameState == GameState.GameEnd)
{
if(PictureList[_firstRevealedPic].gameObject.activeSelf == false &&
PictureList[_secondRevealedPic].gameObject.activeSelf == false &&
EndGamePanel.activeSelf == false)
{
ShowEndGameInformation();
if (GameSettings.Instance.IsSoundEffectMutedPermanently() == false)
WinSound.Play();
//BgSound.Pause();
}
}
}
}
private bool CheckGameEnd()
{
if(_removedPairs == _pairNumbers && CurrentGameState != GameState.GameEnd)
{
CurrentGameState = GameState.GameEnd;
_gameTimer.StopTimer();
Config.PlaceScoreOnBorad(_gameTimer.GetCurrentTime());
}
return (CurrentGameState == GameState.GameEnd);
}
private void ShowEndGameInformation()
{
EndGamePanel.SetActive(true);
if(Config.IsBestScore())
{
NewBestScoreText.SetActive(true);
YourScoreText.SetActive(false);
}
else
{
NewBestScoreText.SetActive(false);
YourScoreText.SetActive(true);
}
var timer = _gameTimer.GetCurrentTime();
var minutes = Mathf.Floor(timer / 60);
var seconds = Mathf.RoundToInt(timer % 60);
var newText = minutes.ToString("00") + ":" + seconds.ToString("00");
EndTimeText.GetComponent<Text>().text = newText;
}
private void SpwanPictureMesh(int rows, int columns, Vector2 Pos, Vector2 offset, bool scaleDown)
{
for(int col = 0; col < columns; col++)
{
for(int row = 0; row < rows; row++)
{
var tempPicture = (Picture)Instantiate(PicturePrefab, PicSpawnPosition.position, PicturePrefab.transform.rotation);
if(scaleDown)
{
tempPicture.transform.localScale = _newScaleDown;
}
tempPicture.name = tempPicture.name + 'c' + col + 'r' + row;
PictureList.Add(tempPicture);
}
}
ApplyTextures();
}
public void ApplyTextures()
{
var rndMatIndex = Random.Range(0, _materialList.Count);
var AppliedTimes = new int[_materialList.Count];
for(int i = 0; i< _materialList.Count; i++)
{
AppliedTimes[i] = 0;
}
foreach(var o in PictureList)
{
var randPrevious = rndMatIndex;
var counter = 0;
var forceMat = false;
while(AppliedTimes[rndMatIndex] >= 2 || ((randPrevious == rndMatIndex) && !forceMat))
{
rndMatIndex = Random.Range(0, _materialList.Count);
counter++;
if(counter > 100)
{
for (var j = 0; j < _materialList.Count; j++)
{
if(AppliedTimes[j] < 2)
{
rndMatIndex = j;
forceMat = true;
}
}
if (forceMat == false)
return;
}
}
o.SetFirstMaterial(_firstMaterial, _firstTexturePath);
o.ApplyFirstMaterial();
o.SetSecondMaterial(_materialList[rndMatIndex], _texturePathList[rndMatIndex]);
o.SetIndex(rndMatIndex);
o.Revealed = false;
AppliedTimes[rndMatIndex] += 1;
forceMat = false;
}
}
private void MovePicture(int rows, int columns, Vector2 pos, Vector2 offset)
{
var index = 0;
for(var col = 0; col < columns; col++)
{
for(int row = 0; row < rows; row++)
{
var targetPosition = new Vector3((pos.x + (offset.x * row)), (pos.y - (offset.y * col)), 0.0f);
StartCoroutine(MoveToPosition(targetPosition, PictureList[index]));
index++;
}
}
}
private IEnumerator MoveToPosition(Vector3 target, Picture obj)
{
var randomDis = 7;
while(obj.transform.position !=target)
{
obj.transform.position = Vector3.MoveTowards(obj.transform.position, target, randomDis * Time.deltaTime);
yield return 0;
}
}
}
----------------------------------------------
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Picture : MonoBehaviour
{
public AudioClip PressSound;
private Material _firstMaterial;
private Material _secondMaterial;
private Quaternion _currentRotation;
[HideInInspector] public bool Revealed = false;
private PictureManager _pictureManager;
private bool _clicked = false;
private int _index;
private AudioSource _audio;
public void SetIndex(int id)
{
_index = id;
}
public int GetIndex()
{
return _index;
}
void Start()
{
Revealed = false;
_clicked = false;
_pictureManager = GameObject.Find("[PictureManager]").GetComponent<PictureManager>();
_currentRotation = gameObject.transform.rotation;
_audio = GetComponent<AudioSource>();
_audio.clip = PressSound;
}
void Update()
{
}
private void OnMouseDown()
{
if(_clicked == false)
{
if (PauseMenu.isPaused == false)
{
_pictureManager.CurrentPuzzleState = PictureManager.PuzzleState.PuzzleRotating;
if (GameSettings.Instance.IsSoundEffectMutedPermanently() == false)
_audio.Play();
StartCoroutine(LoopRotation(45, false));
_clicked = true;
}
}
}
public void FlipBack()
{
if (gameObject.activeSelf)
{
_pictureManager.CurrentPuzzleState = PictureManager.PuzzleState.PuzzleRotating;
Revealed = false;
/*if (GameSettings.Instance.IsSoundEffectMutedPermanently() == false)
_audio.Play();*/
StartCoroutine(LoopRotation(45, true));
}
}
IEnumerator LoopRotation(float angle, bool FirstMat)
{
var rot = 0f;
const float dir = 1f;
const float rotSpeed = 180.0f;
const float rotSpeed1 = 90.0f;
var startAngle = angle;
var assigned = false;
if(FirstMat)
{
while(rot < angle)
{
var step = Time.deltaTime * rotSpeed1;
gameObject.GetComponent<Transform>().Rotate(new Vector3(0, 2, 0) * step * dir);
if(rot >= (startAngle - 2) && assigned == false)
{
ApplyFirstMaterial();
assigned = true;
}
rot += (1 * step * dir);
yield return null;
}
}
else
{
while (angle > 0)
{
float step = Time.deltaTime * rotSpeed;
gameObject.GetComponent<Transform>().Rotate(new Vector3(0, 2, 0) * step * dir);
angle -= (1 * step * dir);
yield return null;
}
}
gameObject.GetComponent<Transform>().rotation = _currentRotation;
if (!FirstMat)
{
Revealed = true;
ApplySecondMaterial();
_pictureManager.CheckPicture();
}
else
{
_pictureManager.PuzzleRevealedNumber = PictureManager.RevealedState.NoRevealed;
_pictureManager.CurrentPuzzleState = PictureManager.PuzzleState.CanRotate;
}
_clicked = false;
}
public void SetFirstMaterial(Material mat, string texturePath)
{
_firstMaterial = mat;
_firstMaterial.mainTexture = Resources.Load(texturePath, typeof(Texture2D)) as Texture2D;
}
public void SetSecondMaterial(Material mat, string texturePath)
{
_secondMaterial = mat;
_secondMaterial.mainTexture = Resources.Load(texturePath, typeof(Texture2D)) as Texture2D;
}
public void ApplyFirstMaterial()
{
gameObject.GetComponent<Renderer>().material = _firstMaterial;
}
public void ApplySecondMaterial()
{
gameObject.GetComponent<Renderer>().material = _secondMaterial;
}
public void Deactivate()
{
StartCoroutine(DeactivateCorutine());
}
private IEnumerator DeactivateCorutine()
{
Revealed = false;
yield return new WaitForSeconds(1f);
gameObject.SetActive(false);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PictureManager : MonoBehaviour
{
public Picture PicturePrefab;
public Transform PicSpawnPosition;
public Vector2 StartPosition = new Vector2(-2.15f, 3.62f);
public AudioSource WinSound;
public AudioSource BgSound;
[Space]
[Header("End Game Screen")]
public GameObject EndGamePanel;
public GameObject NewBestScoreText;
public GameObject YourScoreText;
public GameObject EndTimeText;
/*to rremove
public List<AudioClip> Vegetabels = new List<AudioClip>();
private AudioSource audioSource;
to remove*/
public enum GameState
{
NoAction,
MovingOnPositions,
DeletingPuzzles,
FlipBack,
Checking,
GameEnd
};
public enum PuzzleState
{
PuzzleRotating,
CanRotate,
};
public enum RevealedState
{
NoRevealed,
OneRevealed,
TwoRevealed
};
[HideInInspector]
public GameState CurrentGameState;
[HideInInspector]
public PuzzleState CurrentPuzzleState;
[HideInInspector]
public RevealedState PuzzleRevealedNumber;
[HideInInspector]
public List<Picture> PictureList;
private Vector2 _offset = new Vector2(1.42f, 1.52f);
private Vector2 _offsetFor15Pairs = new Vector2(1.08f, 1.22f);
private Vector2 _offsetFor20Pairs = new Vector2(1.08f, 1.0f);
private Vector3 _newScaleDown = new Vector3(0.9f, 0.9f, 0.001f);
private List<Material> _materialList = new List<Material>();
private List<string> _texturePathList = new List<string>();
private Material _firstMaterial;
private string _firstTexturePath;
private int _firstRevealedPic;
private int _secondRevealedPic;
private int _revealedPicNumber = 0;
private int _picToDestroy1;
private int _picToDestroy2;
private bool _corutineStarted = false;
private int _pairNumbers;
private int _removedPairs;
private Timer _gameTimer;
void Start()
{
//BgSound.Play();
CurrentGameState = GameState.NoAction;
CurrentPuzzleState = PuzzleState.CanRotate;
PuzzleRevealedNumber = RevealedState.NoRevealed;
_revealedPicNumber = 0;
_firstRevealedPic = -1;
_secondRevealedPic = -1;
_removedPairs = 0;
_pairNumbers = (int)GameSettings.Instance.GetPairNumber();
_gameTimer = GameObject.Find("Main Camera").GetComponent<Timer>();
LoadMaterials();
if(GameSettings.Instance.GetPairNumber()== GameSettings.EPairNumber.E10Pairs)
{
CurrentGameState = GameState.MovingOnPositions;
SpwanPictureMesh(4, 5, StartPosition, _offset, false);
MovePicture(4, 5, StartPosition, _offset);
}
else if (GameSettings.Instance.GetPairNumber() == GameSettings.EPairNumber.E15Pairs)
{
CurrentGameState = GameState.MovingOnPositions;
SpwanPictureMesh(5, 6, StartPosition, _offset, false);
MovePicture(5, 6, StartPosition, _offsetFor15Pairs);
}
else if (GameSettings.Instance.GetPairNumber() == GameSettings.EPairNumber.E20Pairs)
{
CurrentGameState = GameState.MovingOnPositions;
SpwanPictureMesh(5, 8, StartPosition, _offset, true);
MovePicture(5, 8, StartPosition, _offsetFor20Pairs);
}
}
public void CheckPicture()
{
CurrentGameState = GameState.Checking;
_revealedPicNumber = 0;
for(int id = 0; id < PictureList.Count; id++)
{
if(PictureList[id].Revealed && _revealedPicNumber < 2)
{
if(_revealedPicNumber == 0)
{
_firstRevealedPic = id;
_revealedPicNumber++;
//audioSource.PlayOneShot(Vegetabels[id]);
}
else if (_revealedPicNumber == 1)
{
_secondRevealedPic = id;
_revealedPicNumber++;
}
}
if (_revealedPicNumber == 2)
{
if (PictureList[_firstRevealedPic].GetIndex() == PictureList[_secondRevealedPic].GetIndex() && _firstRevealedPic != _secondRevealedPic)
{
CurrentGameState = GameState.DeletingPuzzles;
_picToDestroy1 = _firstRevealedPic;
_picToDestroy2 = _secondRevealedPic;
}
else
{
CurrentGameState = GameState.FlipBack;
}
}
}
CurrentPuzzleState = PictureManager.PuzzleState.CanRotate;
if(CurrentGameState == GameState.Checking)
{
CurrentGameState = GameState.NoAction;
}
}
private void DestroyPicture()
{
PuzzleRevealedNumber = RevealedState.NoRevealed;
PictureList[_picToDestroy1].Deactivate();
PictureList[_picToDestroy2].Deactivate();
_revealedPicNumber = 0;
_removedPairs++;
CurrentGameState = GameState.NoAction;
CurrentPuzzleState = PuzzleState.CanRotate;
}
private IEnumerator FlipBack()
{
_corutineStarted = true;
yield return new WaitForSeconds(0.5f);
PictureList[_firstRevealedPic].FlipBack();
PictureList[_secondRevealedPic].FlipBack();
PictureList[_firstRevealedPic].Revealed = false;
PictureList[_secondRevealedPic].Revealed = false;
PuzzleRevealedNumber = RevealedState.NoRevealed;
CurrentGameState = GameState.NoAction;
_corutineStarted = false;
}
private void LoadMaterials()
{
var materialFilePath = GameSettings.Instance.GetMaterialDirectoryName();
var textureFilePath = GameSettings.Instance.GetPuzzleCategoryTextureDirectoryName();
var pairNumber = (int)GameSettings.Instance.GetPairNumber();
const string matBaseName = "Pic";
var firstMaterialName = "Back";
for(var index = 1; index <= pairNumber; index++)
{
var currentFilePath = materialFilePath + matBaseName + index;
Material mat = Resources.Load(currentFilePath, typeof(Material)) as Material;
_materialList.Add(mat);
var currentTextureFilePath = textureFilePath + matBaseName + index;
_texturePathList.Add(currentTextureFilePath);
}
_firstTexturePath = textureFilePath + firstMaterialName;
_firstMaterial = Resources.Load(materialFilePath + firstMaterialName, typeof(Material)) as Material;
}
void Update()
{
if (PauseMenu.isPaused == false) {
if (CurrentGameState == GameState.DeletingPuzzles)
{
if(CurrentPuzzleState == PuzzleState.CanRotate)
{
DestroyPicture();
CheckGameEnd();
}
}
if (CurrentGameState == GameState.FlipBack)
{
if(CurrentPuzzleState == PuzzleState.CanRotate && _corutineStarted == false)
{
StartCoroutine(FlipBack());
}
}
if(CurrentGameState == GameState.GameEnd)
{
if(PictureList[_firstRevealedPic].gameObject.activeSelf == false &&
PictureList[_secondRevealedPic].gameObject.activeSelf == false &&
EndGamePanel.activeSelf == false)
{
ShowEndGameInformation();
if (GameSettings.Instance.IsSoundEffectMutedPermanently() == false)
WinSound.Play();
//BgSound.Pause();
}
}
}
}
private bool CheckGameEnd()
{
if(_removedPairs == _pairNumbers && CurrentGameState != GameState.GameEnd)
{
CurrentGameState = GameState.GameEnd;
_gameTimer.StopTimer();
Config.PlaceScoreOnBorad(_gameTimer.GetCurrentTime());
}
return (CurrentGameState == GameState.GameEnd);
}
private void ShowEndGameInformation()
{
EndGamePanel.SetActive(true);
if(Config.IsBestScore())
{
NewBestScoreText.SetActive(true);
YourScoreText.SetActive(false);
}
else
{
NewBestScoreText.SetActive(false);
YourScoreText.SetActive(true);
}
var timer = _gameTimer.GetCurrentTime();
var minutes = Mathf.Floor(timer / 60);
var seconds = Mathf.RoundToInt(timer % 60);
var newText = minutes.ToString("00") + ":" + seconds.ToString("00");
EndTimeText.GetComponent<Text>().text = newText;
}
private void SpwanPictureMesh(int rows, int columns, Vector2 Pos, Vector2 offset, bool scaleDown)
{
for(int col = 0; col < columns; col++)
{
for(int row = 0; row < rows; row++)
{
var tempPicture = (Picture)Instantiate(PicturePrefab, PicSpawnPosition.position, PicturePrefab.transform.rotation);
if(scaleDown)
{
tempPicture.transform.localScale = _newScaleDown;
}
tempPicture.name = tempPicture.name + 'c' + col + 'r' + row;
PictureList.Add(tempPicture);
}
}
ApplyTextures();
}
public void ApplyTextures()
{
var rndMatIndex = Random.Range(0, _materialList.Count);
var AppliedTimes = new int[_materialList.Count];
for(int i = 0; i< _materialList.Count; i++)
{
AppliedTimes[i] = 0;
}
foreach(var o in PictureList)
{
var randPrevious = rndMatIndex;
var counter = 0;
var forceMat = false;
while(AppliedTimes[rndMatIndex] >= 2 || ((randPrevious == rndMatIndex) && !forceMat))
{
rndMatIndex = Random.Range(0, _materialList.Count);
counter++;
if(counter > 100)
{
for (var j = 0; j < _materialList.Count; j++)
{
if(AppliedTimes[j] < 2)
{
rndMatIndex = j;
forceMat = true;
}
}
if (forceMat == false)
return;
}
}
o.SetFirstMaterial(_firstMaterial, _firstTexturePath);
o.ApplyFirstMaterial();
o.SetSecondMaterial(_materialList[rndMatIndex], _texturePathList[rndMatIndex]);
o.SetIndex(rndMatIndex);
o.Revealed = false;
AppliedTimes[rndMatIndex] += 1;
forceMat = false;
}
}
private void MovePicture(int rows, int columns, Vector2 pos, Vector2 offset)
{
var index = 0;
for(var col = 0; col < columns; col++)
{
for(int row = 0; row < rows; row++)
{
var targetPosition = new Vector3((pos.x + (offset.x * row)), (pos.y - (offset.y * col)), 0.0f);
StartCoroutine(MoveToPosition(targetPosition, PictureList[index]));
index++;
}
}
}
private IEnumerator MoveToPosition(Vector3 target, Picture obj)
{
var randomDis = 7;
while(obj.transform.position !=target)
{
obj.transform.position = Vector3.MoveTowards(obj.transform.position, target, randomDis * Time.deltaTime);
yield return 0;
}
}
}
Related
My program gives the user the option to serialize a certain list List<Position>ListPosition that stores the data from the class Position. It does serialize pretty well and it sorta looks like the following
{
"PosZ": 0,
"PosX": 749,
"PosY": 208,
"Agent": {
"IsEdgeTree": false,
"ThisTreesCreator": null,
"Type": 0,
"Colour": "Green",
"Dimension": 25
}
},
{
"PosZ": 0,
"PosX": 724,
"PosY": 183,
"Agent": {
"IsEdgeTree": false,
"ThisTreesCreator": {
"IsEdgeTree": false,
"Position": {
"PosZ": 0,
"PosX": 749,
"PosY": 208
},
"ThisTreesCreator": null,
"Type": 0,
"Colour": "Green",
"Dimension": 25
},
"Type": 0,
"Colour": "Green",
"Dimension": 25
}
},
These are just a few examples.
The bit that is giving me problems is when I deserialize it.
When I inspect the bit of code that converts it JsonConvert.DeserializeObject<List<Position>>(JsonString);, everything reads fine but, when I equal it to the List I am trying to dump the data to AKA the same list the serialized data comes from but empty, the data doesn't load and I'm left with the correct structure but no values.
Values not showing up
To Deserialize, I call the following method from another Windows Forms:
public static void Deserialize()
{
if (Directory.Exists("Serialized"))
{
var FileName = "Serialized/PositionsSerialized_4.json";
var JsonString = File.ReadAllText(FileName);
ListPositions = JsonConvert.DeserializeObject<List<Position>>(JsonString);
}
else
MessageBox.Show("There's no directory");
}
I would really appreciate some help. If more information is needed, be sure to request it in the comments.
Thank you for your time.
public class Position
{
public static int MaxX { get; private set; }
public static int MaxY { get; private set; }
public static List<Position> ListPositions { get; private set; }
public static List<Position> ListTreePositions {
get
{
return ListPositions.Where(w => w.Agent?.Type == AgentType.Tree).ToList();
}
}
public static List<Position> ListDronePositions
{
get
{
return ListPositions.Where(w => w.Agent?.Type == AgentType.Drone).ToList();
}
}
public int PosX { get; private set; }
public int PosY { get; private set; }
public int PosZ;
private static object services;
public Agent Agent { get; private set; }
public Position()
{
ListPositions = new List<Position>();
}
public static void SetMaxValues(int maxX, int maxY)
{
MaxX = maxX;
MaxY = maxY;
}
public void FillNeighbours(int posX, int posY, int dim)
{
for (int i = 0; i < dim; i++)
{
for (int y = 0; y < dim; y++)
{
new Position(posX - (dim - y), posY - (dim - i), Agent);
}
}
}
public static Position CreateNewRandomPosition()
{
Random rnd = new Random();
int rndX;
int rndY;
Position position = null;
while (position == null)
{
rndX = rnd.Next(MaxX - 100);
rndY = rnd.Next(MaxY - 100);
position = CreatePosition(rndX, rndY);
}
return position;
}
public static Bitmap ExportBitmap()
{
return ExportBitmap(0, 0, MaxX, MaxY, ListPositions);
}
public static Bitmap ExportBitmap(int posX, int posY, int maxX, int maxY)
{
var listPositions = ListPositions.Where(w => (w.Agent != null) && (w.PosX >= posX && w.PosX <= maxX) && (w.PosY >= posY && w.PosY <= maxY)).ToList();
return ExportBitmap(posX, posY, maxX, maxY, listPositions);
}
public static Bitmap ExportBitmap(int posX, int posY, int maxX, int maxY, AgentType agentType)
{
var listPositions = ListPositions.Where(w => (w.Agent.Type == agentType) && (w.PosX >= posX && w.PosX <= maxX) && (w.PosY >= posY && w.PosY <= maxY)).ToList();
return ExportBitmap(posX, posY, maxX, maxY, listPositions);
}
public static Bitmap ExportBitmap(int posX, int posY, int maxX, int maxY, AgentType[] agentType)
{
var listPositions = ListPositions.Where(w => (agentType.Contains(w.Agent.Type)) && (w.PosX >= posX && w.PosX <= maxX) && (w.PosY >= posY && w.PosY <= maxY)).ToList();
return ExportBitmap(posX, posY, maxX, maxY, listPositions);
}
private static Bitmap ExportBitmap(int posX, int posY, int maxX, int maxY, List<Position> positions)
{
Bitmap bmp = new Bitmap(maxX - posX, maxY - posY);
if (Agent.Sprites.Count() == 0)
{
Agent.LoadSprites();
}
Graphics g = Graphics.FromImage(bmp);
foreach (var item in positions)
{
var SpriteWidth = Agent.Sprites[item.Agent.Type].Width / 2;
var SpriteHeight = Agent.Sprites[item.Agent.Type].Height / 2;
g.DrawImage(Agent.Sprites[item.Agent.Type], new Point(item.PosX - SpriteWidth - posX, item.PosY - SpriteHeight - posY));
}
if (!Directory.Exists("Photos"))
{
Directory.CreateDirectory("Photos");
}
int count = Directory.GetFiles("Photos", "*").Length;
bmp.Save("Photos\\Img" + count + 1 + ".png", System.Drawing.Imaging.ImageFormat.Png);
return bmp;
}
public Position(int poxX, int poxY)
{
PosX = poxX;
PosY = poxY;
if (Agent != null)
ListPositions.Add(this);
}
public Position(int posX, int posY, Agent agent)
{
PosX = posX;
PosY = posY;
Agent = agent;
if (Agent != null)
ListPositions.Add(this);
}
public void AssociateAgent(Agent agent)
{
Agent = agent;
if (Agent != null)
ListPositions.Add(this);
}
public static bool CheckPositionIsValid(int poxX, int poxY)
{
int? NullableMaxX = MaxX;
int? NullableMaxY = MaxY;
var posXValid = poxX > 0 && (poxX <= MaxX || NullableMaxX == null); //verifies if posX is within the boundries of the premises
var posYValid = poxY > 0 && (poxY <= MaxY || NullableMaxY == null); //verifies if posY is within the boundries of the premises
return posXValid && posYValid; //returns if they are both valid
}
public static Position Find(int poxX, int poxY)
{
return ListPositions.Find(f => f.PosX == poxX && f.PosY == poxY) ?? null;
}
public static Position CreatePosition(int poxX, int poxY)
{
if (Find(poxX, poxY) == null)
if (CheckPositionIsValid(poxX, poxY))
return new Position(poxX, poxY);
else
return null;
else
return null;
}
public Dictionary<int, Position> ListNeighbourPositions(int dim = 1)
{
Dictionary<int, Position> NeighbourList = new Dictionary<int, Position>();
for (int i = 1; i < 9; i++)
{
if (i != 5)
{
var position = FindNeighbour(i, dim);
if (position != null)
NeighbourList.Add(i, position);
}
}
return NeighbourList;
}
public Position FindNeighbour(int neighbourPos, int dim)
{
var position = FindNeighbourbyPosition(neighbourPos, dim);
return Find(position.Item1, position.Item2);
}
public Tuple<int, int> FindNeighbourbyPosition(int neighbourPos, int dim = 1)
{
int neighbourPosX;
int neighbourPosY;
switch (neighbourPos)
{
case 1:
neighbourPosX = PosX - dim;
neighbourPosY = PosY - dim;
break;
case 2:
neighbourPosX = PosX;
neighbourPosY = PosY - dim;
break;
case 3:
neighbourPosX = PosX + dim;
neighbourPosY = PosY - dim;
break;
case 4:
neighbourPosX = PosX - dim;
neighbourPosY = PosY;
break;
case 6:
neighbourPosX = PosX + dim;
neighbourPosY = PosY;
break;
case 7:
neighbourPosX = PosX - dim;
neighbourPosY = PosY + dim;
break;
case 8:
neighbourPosX = PosX;
neighbourPosY = PosY + dim;
break;
case 9:
neighbourPosX = PosX + dim;
neighbourPosY = PosY + dim;
break;
default:
return null;
}
return new Tuple<int, int>(neighbourPosX, neighbourPosY);
}
public void UpdatePosition(int newX, int newY)
{
PosX = newX;
PosY = newY;
}
public static void Serialize()
{
if (!Directory.Exists("Serialized"))
{
Directory.CreateDirectory("Serialized");
}
int count = Directory.GetFiles("Serialized", "*").Length;
string fileName = "Serialized/PositionsSerialized_" + count + ".json";
string jsonString = JsonConvert.SerializeObject(ListPositions, Formatting.Indented, new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
File.WriteAllText(fileName, jsonString);
}
public static void Deserialize()
{
if (Directory.Exists("Serialized"))
{
var FileName = "Serialized/PositionsSerialized_4.json";
var JsonString = File.ReadAllText(FileName);
ListPositions = JsonConvert.DeserializeObject<List<Position>>(JsonString);
}
else
MessageBox.Show("There's no directory");
}
}
The reason of your problem is because you defined setters as private...
public static int MaxX { get; private set; }
public static int MaxY { get; private set; }
public int PosX { get; private set; }
public int PosY { get; private set; }
it should be...
public static int MaxX { get; set; }
public static int MaxY { get; set; }
public int PosX { get; set; }
public int PosY { get; set; }
So I am using Unity c# and this asset for this question -> https://assetstore.unity.com/packages/tools/gui/inventory-system-full-126053.
The asset does not have a feature for using an item thought, so I want to use these lines of prewritten code.
public bool FindMetaData(string type, string metaData)
{
foreach (Slot slot in inventory)
if (slot.type == type && slot.metaData == metaData)
return true;
foreach (Slot slot in hotbar)
if (slot.type == type && slot.metaData == metaData)
return true;
return false;
}
My problem is that I haveno idea how I could combine this with anything, or if there is even a better solution to creating a better system.
Hence I want to ask you if you guys could give me an d example, if I would want to look for the metadata "Example". Here is the rest of the code from the inventory system:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class QuantumInventory : MonoBehaviour
{
[System.NonSerialized] public List<Slot> inventory, hotbar, slots;
public int maxSlots;
public KeyCode interact, action;
public AudioClip open, close, pickUp, moveSlot, drop;
public float distance;
public bool inventoryToggle = false;
GameObject inventoryObj;
GameObject[] go;
// [0 SLOT][1 INVENTORY][2 HOTBAR][3 ITEM]
Transform[] t;
// [0 CONTAINER][1 INVENTORY][2 HOTBAR][3 SLOTS][4 OPTIONS][5 DOC VIEW]
Sprite error;
bool o;
Transform playerCamera, canvas, invSlots;
PlayerMove pm;
PlayerLook pl;
CanvasScaler cs;
Dropdown sort;
Text info;
QuantumContainer quantumContainer;
private void Start()
{
o = !o;
inventory = new List<Slot>();
hotbar = new List<Slot>();
slots = new List<Slot>();
foreach (Transform child in transform)
if (child.GetComponent<Camera>() != null)
playerCamera = child;
foreach (Transform child in transform)
if (child.GetComponent<PlayerLook>() != null)
pl = child.GetComponent<PlayerLook>();
if (GetComponent<PlayerMove>() != null)
pm = GetComponent<PlayerMove>();
if (maxSlots > 40)
maxSlots = 40;
canvas = GameObject.Find("Canvas").transform;
cs = canvas.GetComponent<CanvasScaler>();
cs.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
cs.referenceResolution = new Vector2(1280, 720);
cs.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
cs.matchWidthOrHeight = 0.5f;
go = new GameObject[5];
t = new Transform[7];
go[0] = Resources.Load<GameObject>("Core/QIS/_slot");
go[1] = Resources.Load<GameObject>("Core/QIS/_inventory");
go[2] = Resources.Load<GameObject>("Core/QIS/_hotbar");
go[3] = Resources.Load<GameObject>("Core/QIS/_erit");
error = Resources.Load<Sprite>("Core/QIS/_ertex");
t[1] = Instantiate<GameObject>(go[1], canvas).transform;
invSlots = t[1].Find("_slots");
t[0] = t[1].Find("_container");
t[4] = t[1].Find("_options");
t[3] = t[4].Find("_moreSlots");
t[5] = t[1].Find("_docViewer");
t[2] = Instantiate<GameObject>(go[2], canvas).transform;
t[6] = t[4].Find("_info");
sort = t[4].Find("_sort").GetComponent<Dropdown>();
sort.GetComponent<Dropdown>().onValueChanged.AddListener(delegate { RefreshInventory(); });
info = t[6].Find("Text").GetComponent<Text>();
t[1].gameObject.SetActive(false);
}
private void Update()
{
if (Input.GetKeyDown(interact))
{
RaycastHit hit;
int layer = gameObject.layer;
gameObject.layer = 2;
if (Physics.Raycast(playerCamera.position, playerCamera.forward, out hit, distance))
{
if (hit.collider.GetComponent<QuantumItem>() != null)
Gather(hit.collider.GetComponent<QuantumItem>());
else if (hit.collider.GetComponent<QuantumContainer>() != null)
Container(hit.collider.GetComponent<QuantumContainer>());
}
gameObject.layer = layer;
}
if (Input.GetKeyDown(action))
{
Freeze();
ActionInventory();
SetActive(false, true, false);
}
// links function to update
UseItems();
}
public void Freeze()
{
o = !o;
if (pm != null && pl != null)
{ pm.enabled = o; pl.enabled = o; }
if (o)
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
Time.timeScale = 1;
}
else
{
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
Time.timeScale = 0f;
}
}
public void Container(QuantumContainer container)
{
if (container.locked != "")
{
if (!FindMetaData("Key", container.locked))
{
container.PlayFX(container.lockState);
return;
}
}
Freeze();
ActionInventory();
SetActive(true, false, false);
quantumContainer = container;
quantumContainer.PlayFX(quantumContainer.open);
RefreshInventory();
}
public void ActionInventory()
{
t[1].gameObject.SetActive(!o);
if (t[1].gameObject.activeSelf)
PlayFX(open);
else
PlayFX(close);
if (t[0].gameObject.activeSelf)
quantumContainer.PlayFX(quantumContainer.close);
SetActive(false, true, false);
RefreshInventory();
}
private void DeNuller ()
{
foreach (Transform child in invSlots)
Destroy(child.gameObject);
foreach (Transform child in t[0])
Destroy(child.gameObject);
foreach (Transform child in t[2])
Destroy(child.gameObject);
foreach (Transform child in t[3])
Destroy(child.gameObject);
}
private void RefreshInventory()
{
DeNuller();
if (sort.value == 0) //NORMAL
{
foreach (Slot slot in inventory)
{
GameObject x = Instantiate(go[0], invSlots);
if (slot.icon != null)
x.transform.Find("Icon").GetComponent<Image>().sprite = slot.icon;
else
x.transform.Find("Icon").GetComponent<Image>().sprite = error;
x.transform.Find("Type").GetComponent<Image>().sprite = Resources.Load<Sprite>("Core/QIS/" + slot.type);
if (slot.quantity > 1)
x.transform.Find("Text").GetComponent<Text>().text = slot.quantity.ToString("");
else
x.transform.Find("Text").GetComponent<Text>().text = "";
x.GetComponent<Button>().onClick.AddListener(delegate { Action(slot); });
}
}
else // TYPE [ITEM-DOCUMENT-KEY-CONSUMABLE-SLOT-CUSTOM]
{
InstantiateSlot("Item");
InstantiateSlot("Document");
InstantiateSlot("Key");
InstantiateSlot("Consumable");
InstantiateSlot("Slot");
InstantiateSlot("Custom");
}
foreach (Slot slot in hotbar)
{
GameObject x = Instantiate(go[0], t[2]);
if (slot.icon != null)
x.transform.Find("Icon").GetComponent<Image>().sprite = slot.icon;
else
x.transform.Find("Icon").GetComponent<Image>().sprite = error;
x.transform.Find("Type").GetComponent<Image>().sprite = Resources.Load<Sprite>("Core/QIS/" + slot.type);
if (slot.quantity != 1)
x.transform.Find("Text").GetComponent<Text>().text = slot.quantity.ToString("");
else
x.transform.Find("Text").GetComponent<Text>().text = "";
x.GetComponent<Button>().onClick.AddListener(delegate { HotbarAction(slot); });
}
foreach (Slot slot in slots)
{
GameObject x = Instantiate(go[0], t[3]);
if (slot.icon != null)
x.transform.Find("Icon").GetComponent<Image>().sprite = slot.icon;
else
x.transform.Find("Icon").GetComponent<Image>().sprite = error;
x.transform.Find("Type").GetComponent<Image>().sprite = Resources.Load<Sprite>("Core/QIS/" + slot.type);
if (slot.quantity != 1)
x.transform.Find("Text").GetComponent<Text>().text = slot.quantity.ToString("");
else
x.transform.Find("Text").GetComponent<Text>().text = "";
x.GetComponent<Button>().onClick.AddListener(delegate { SlotAction(slot); });
}
if (t[0].gameObject.activeSelf)
{
foreach (Slot slot in quantumContainer.inventory)
{
GameObject x = Instantiate(go[0], t[0]);
if (slot.icon != null)
x.transform.Find("Icon").GetComponent<Image>().sprite = slot.icon;
else
x.transform.Find("Icon").GetComponent<Image>().sprite = error;
x.transform.Find("Type").GetComponent<Image>().sprite = Resources.Load<Sprite>("Core/QIS/" + slot.type);
if (slot.quantity != 1)
x.transform.Find("Text").GetComponent<Text>().text = slot.quantity.ToString("");
else
x.transform.Find("Text").GetComponent<Text>().text = "";
x.GetComponent<Button>().onClick.AddListener(delegate { ContainerAction(slot); });
}
}
info.text = "Max Slots: " + maxSlots;
info.text += "\nUsed Slots: " + inventory.Count;
info.text += "\nFree Slots: " + (maxSlots - inventory.Count);
info.text += "\n\nHotbar Max Slots: 9";
info.text += "\nHotbar Used Space: " + hotbar.Count;
info.text += "\nHotbar Free Space: " + (9 - hotbar.Count);
int additionalSlots = 0;
foreach (Slot slot in slots)
additionalSlots += int.Parse(slot.metaData);
info.text += "\n\nAdditional Slots: " + additionalSlots;
}
private void InstantiateSlot(string type)
{
foreach (Slot slot in inventory)
{
if (slot.type == type)
{
GameObject x = Instantiate(go[0], invSlots);
if (slot.icon != null)
x.transform.Find("Icon").GetComponent<Image>().sprite = slot.icon;
else
x.transform.Find("Icon").GetComponent<Image>().sprite = error;
x.transform.Find("Type").GetComponent<Image>().sprite = Resources.Load<Sprite>("Core/QIS/" + slot.type);
if (slot.quantity != 1)
x.transform.Find("Text").GetComponent<Text>().text = slot.quantity.ToString("");
else
x.transform.Find("Text").GetComponent<Text>().text = "";
x.GetComponent<Button>().onClick.AddListener(delegate { Action(slot); });
}
}
}
private void Action(Slot slot)
{
if (Input.GetKey(KeyCode.LeftControl))
{
Drop(slot);
inventory.Remove(slot);
PlayFX(moveSlot);
}
else
{
if (t[0].gameObject.activeSelf)
{
if (quantumContainer.inventory.Count >= quantumContainer.maxSlots)
return;
quantumContainer.Gather(slot);
inventory.Remove(slot);
PlayFX(moveSlot);
}
else
{
switch (slot.type)
{
case "Document":
SetActive(false, false, true);
t[5].Find("Text").GetComponent<Text>().text = slot.metaData;
break;
case "Slot":
SetActive(false, true, false);
ChangeMaxSlots(int.Parse(slot.metaData));
slots.Add(slot);
inventory.Remove(slot);
PlayFX(moveSlot);
break;
default:
if (hotbar.Count >= 9)
return;
GatherHotbar(slot);
inventory.Remove(slot);
PlayFX(moveSlot);
break;
}
}
}
RefreshInventory();
}
private void HotbarAction(Slot slot)
{
if (Input.GetKey(KeyCode.LeftControl))
{
Drop(slot);
hotbar.Remove(slot);
PlayFX(drop);
}
else
{
if (t[0].gameObject.activeSelf)
{
if (quantumContainer.inventory.Count >= quantumContainer.maxSlots)
return;
quantumContainer.Gather(slot);
hotbar.Remove(slot);
PlayFX(moveSlot);
}
else
{
if (inventory.Count >= maxSlots)
return;
Gather(slot);
hotbar.Remove(slot);
PlayFX(moveSlot);
}
}
RefreshInventory();
}
private void ContainerAction(Slot slot)
{
if (Input.GetKey(KeyCode.LeftControl))
{
Drop(slot);
quantumContainer.inventory.Remove(slot);
PlayFX(drop);
RefreshInventory();
}
else if (!Input.GetKey(KeyCode.LeftControl) && inventory.Count < maxSlots)
{
Gather(slot);
quantumContainer.inventory.Remove(slot);
PlayFX(moveSlot);
RefreshInventory();
}
}
private void SlotAction(Slot slot)
{
int i = int.Parse(slot.metaData);
ChangeMaxSlots(-i);
if (Input.GetKey(KeyCode.LeftControl))
{
Drop(slot);
slots.Remove(slot);
PlayFX(drop);
RefreshInventory();
}
else if (!Input.GetKey(KeyCode.LeftControl) && inventory.Count < maxSlots)
{
Gather(slot);
slots.Remove(slot);
PlayFX(moveSlot);
RefreshInventory();
}
}
private void ChangeMaxSlots(int quantity)
{
maxSlots += quantity;
if (maxSlots > 40)
maxSlots = 40;
else if (maxSlots < 0)
maxSlots = 0;
}
private void Drop(Slot slot)
{
GameObject x = Resources.Load<GameObject>("Core/QIS/" + slot.item);
if (x == null)
{ x = Instantiate(go[3]); x.GetComponent<Renderer>().material = Resources.Load<Material>("Core/QIS/Materials/_" + slot.type.ToUpper()); }
else
{ Instantiate(x); }
x.transform.position = transform.position;
x.GetComponent<QuantumItem>().item = slot.item;
x.GetComponent<QuantumItem>().type = slot.type;
x.GetComponent<QuantumItem>().quantity = slot.quantity;
if (slot.icon == null)
x.GetComponent<QuantumItem>().icon = error;
else
x.GetComponent<QuantumItem>().icon = slot.icon;
x.GetComponent<QuantumItem>().stackable = slot.stackable;
x.GetComponent<QuantumItem>().metaData = slot.metaData;
}
private void SetActive(bool container, bool options, bool viewer)
{
t[0].gameObject.SetActive(container);
t[4].gameObject.SetActive(options);
t[5].gameObject.SetActive(viewer);
}
public void Gather(QuantumItem item)
{
if (inventory.Count >= maxSlots)
return;
Slot slot = FindSlot(item.item);
if (slot == null || !slot.stackable)
inventory.Add(new Slot(item));
else if (slot != null && slot.stackable && slot.type == item.type)
slot.quantity += item.quantity;
PlayFX(pickUp);
Destroy(item.gameObject);
}
public void Gather(Slot item)
{
if (inventory.Count >= maxSlots)
return;
Slot slot = FindSlot(item.item);
if (slot == null || !slot.stackable)
inventory.Add(item);
else if (slot != null && slot.stackable && slot.type == item.type)
slot.quantity += item.quantity;
PlayFX(pickUp);
}
public void GatherHotbar(Slot item)
{
if (hotbar.Count >= 9)
return;
Slot slot = FindHotbarSlot(item.item);
if (slot == null || !slot.stackable)
hotbar.Add(item);
else if (slot != null && slot.stackable && slot.type == item.type)
slot.quantity += item.quantity;
PlayFX(pickUp);
}
public bool FindItem(string item)
{
foreach (Slot slot in inventory)
if (slot.item == item)
return true;
return false;
}
public bool FindItem(string item, int quantity)
{
foreach (Slot slot in inventory)
if (slot.item == item && slot.quantity >= quantity)
return true;
return false;
}
public Slot FindSlot(string item)
{
foreach (Slot slot in inventory)
if (slot.item == item)
return slot;
return null;
}
public Slot FindHotbarSlot(string item)
{
foreach (Slot slot in hotbar)
if (slot.item == item)
return slot;
return null;
}
public bool FindMetaData(string type, string metaData)
{
foreach (Slot slot in inventory)
if (slot.type == type && slot.metaData == metaData)
return true;
foreach (Slot slot in hotbar)
if (slot.type == type && slot.metaData == metaData)
return true;
return false;
}
public void FindItemAndRemove(string item)
{
foreach (Slot slot in inventory)
if (slot.item == item)
inventory.Remove(slot);
}
public void FindItemAndRemove(string item, int quantity)
{
foreach (Slot slot in inventory)
if (slot.item == item && slot.quantity >= quantity)
{
slot.quantity -= quantity;
if (slot.quantity <= 0)
inventory.Remove(slot);
}
}
public Slot GetHotbarID (int i)
{
return hotbar[i];
}
private void PlayFX(AudioClip fx)
{
if (fx == null)
return;
GameObject obj = new GameObject();
obj.transform.position = transform.position;
AudioSource source = obj.AddComponent<AudioSource>();
source.clip = fx;
source.Play();
Destroy(obj, fx.length);
}
[System.Serializable]
public class Slot
{
public string item, type;
public int quantity;
public Sprite icon;
public bool stackable;
[TextArea(3, 5)]
public string metaData;
public Slot(string item, string type, int quantity, Sprite icon, bool stackable, string metaData)
{
this.item = item;
this.type = type;
this.quantity = quantity;
this.icon = icon;
this.stackable = stackable;
this.metaData = metaData;
}
public Slot(QuantumItem quantum)
{
this.item = quantum.item;
this.type = quantum.type;
this.quantity = quantum.quantity;
this.icon = quantum.icon;
this.stackable = quantum.stackable;
this.metaData = quantum.metaData;
}
}
}
I am working on a project where i turn a DJI drone into a Advanced UAV from call of duty and I'm using unity for it with C# as a client and Python as a server. I am having trouble implementing what i want the code to do.
Basically I want to parse three sets of arrays. each array is corresponding to a cube game object. Based on each game object, I want it to read the correct MQTT messages and assign the array as the transport.position of the current game object based on the game objects name.
My MQTT messages are displaying over console and my code doesn't have any errors as it runs but the blocks don't stay in place rather spawn in and out of location.
Before I added the drone and object location delegates everything spawned fine. where did i go wrong? Posting the code i have below so far. I guess I'm trying to learn where I messed up so I can formulate a proper solution. I am doing this so I can showcase an ability to solve the problem but I'm the only programmer I know so I have no idea what I'm doing wrong or what section of the code I'm messing up on other then I feel like I'm making something redundant.
edit
I think i might have to create pre fabs for each object i anticipate on the field, from there i need to create classes for those objects with get and set methods. I need to also create the script over again for each object.
```lang-csharp
public void Update()
{
while (!_messageQueue.IsEmpty)
{
string message;
if (_messageQueue.TryDequeue(out message))
{
_messageDelegate(message);
}
else
{
break;
}
}
while (!_droneLocationQueue.IsEmpty)
{
string droneLocation;
if (_droneLocationQueue.TryDequeue(out droneLocation))
{
_messageDelegate2(droneLocation);
}
else
{
break;
}
}
while (!_objectLocationQueue.IsEmpty)
{
string objectLocation;
if (_objectLocationQueue.TryDequeue(out objectLocation))
{
_messageDelegate3(objectLocation);
}
else
{
break;
}
}
}
```
```lang-csharp
private void HandleMessage(string message)
{
if (LarTarget.name == GameObject.Find("LarTarget").ToString())
{
var splittedStrings = message.Split(' ');
if (splittedStrings.Length != 3) return;
latitude = float.Parse(splittedStrings[0]);
longitude = float.Parse(splittedStrings[1]);
altitude = float.Parse(splittedStrings[2]);
LarTarget.transform.position = new Vector3(latitude, longitude, altitude);
}
else if(objectLocationTarget.name == GameObject.Find("objectLocationTarget").ToString())
{
var splittedStrings = message.Split(' ');
if (splittedStrings.Length != 3) return;
latitude1 = float.Parse(splittedStrings[0]);
longitude1 = float.Parse(splittedStrings[1]);
altitude1 = float.Parse(splittedStrings[2]);
objectLocationTarget.transform.position = new Vector3(latitude1, longitude1, altitude1);
}
else {
var splittedStrings = message.Split(' ');
if (splittedStrings.Length != 3) return;
latitude2 = float.Parse(splittedStrings[0]);
longitude2 = float.Parse(splittedStrings[1]);
altitude2 = float.Parse(splittedStrings[2]);
droneTarget.transform.position = new Vector3(latitude2, longitude2, altitude2);
}
}
```
full code in this block
```lang-csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections.Concurrent;
using System.Threading;
using NetMQ;
using NetMQ.Sockets;
public class NetMqListener
{
private readonly Thread _listenerWorker;
private readonly Thread _listenerWorker2;
private readonly Thread _listenerWorker3;
private bool _listenerCancelled;
public delegate void MessageDelegate(string message);
public delegate void MessageDelegate2(string droneLocation);
public delegate void MessageDelegate3(string objectLocation);
private readonly MessageDelegate _messageDelegate;
private readonly MessageDelegate2 _messageDelegate2;
private readonly MessageDelegate3 _messageDelegate3;
private readonly ConcurrentQueue<string> _messageQueue = new ConcurrentQueue<string>();
private readonly ConcurrentQueue<string> _droneLocationQueue = new ConcurrentQueue<string>();
private readonly ConcurrentQueue<string> _objectLocationQueue = new ConcurrentQueue<string>();
private void ListenerWork()
{
AsyncIO.ForceDotNet.Force();
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.1.5:12345");
subSocket.Subscribe("");
while (!_listenerCancelled)
{
string frameString;
if (!subSocket.TryReceiveFrameString(out frameString)) continue;
Debug.Log(frameString);
_messageQueue.Enqueue(frameString);
}
subSocket.Close();
}
NetMQConfig.Cleanup();
}
private void ListenerWork2()
{
AsyncIO.ForceDotNet.Force();
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.1.5:12345");
subSocket.Subscribe("");
while (!_listenerCancelled)
{
string frameString2;
if (!subSocket.TryReceiveFrameString(out frameString2)) continue;
Debug.Log(frameString2);
_objectLocationQueue.Enqueue(frameString2);
}
subSocket.Close();
}
NetMQConfig.Cleanup();
}
private void ListenerWork3()
{
AsyncIO.ForceDotNet.Force();
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.1.5:12345");
subSocket.Subscribe("");
while (!_listenerCancelled)
{
string frameString3;
if (!subSocket.TryReceiveFrameString(out frameString3)) continue;
Debug.Log(frameString3);
_droneLocationQueue.Enqueue(frameString3);
}
subSocket.Close();
}
NetMQConfig.Cleanup();
}
public void Update()
{
while (!_messageQueue.IsEmpty)
{
string message;
if (_messageQueue.TryDequeue(out message))
{
_messageDelegate(message);
}
else
{
break;
}
}
while (!_droneLocationQueue.IsEmpty)
{
string droneLocation;
if (_droneLocationQueue.TryDequeue(out droneLocation))
{
_messageDelegate2(droneLocation);
}
else
{
break;
}
}
while (!_objectLocationQueue.IsEmpty)
{
string objectLocation;
if (_objectLocationQueue.TryDequeue(out objectLocation))
{
_messageDelegate3(objectLocation);
}
else
{
break;
}
}
}
public NetMqListener(MessageDelegate messageDelegate, MessageDelegate2 messageDelegate2, MessageDelegate3 messageDelegate3)
{
_messageDelegate = messageDelegate;
_messageDelegate2 = messageDelegate2;
_messageDelegate3 = messageDelegate3;
_listenerWorker = new Thread(ListenerWork);
_listenerWorker2 = new Thread(ListenerWork2);
_listenerWorker3 = new Thread(ListenerWork3);
}
public void Start()
{
_listenerCancelled = false;
_listenerWorker.Start();
_listenerWorker2.Start();
_listenerWorker3.Start();
}
public void Stop()
{
_listenerCancelled = true;
_listenerWorker.Join();
_listenerWorker2.Join();
_listenerWorker3.Join();
}
}
public class LocativeTargetClient : MonoBehaviour
{
[Header("Google Maps Coordinates")]
public float latitude;
public float latitude1;
public float latitude2;
public float longitude;
public float longitude1;
public float longitude2;
public float altitude;
public float altitude1;
public float altitude2;
public GameObject LarTarget;
public GameObject objectLocationTarget;
public GameObject droneTarget;
//[Header("Enable")]
//public float MaximumDistance=1000;
private double raioTerra = 6372797.560856f;
private readonly Thread _listenerWorker;
private readonly Thread _listenerWorker2;
private readonly Thread _listenerWorker3;
private NetMqListener _netMqListener;
private NetMqListener _netMqListener2;
private NetMqListener _netMqListener3;
private bool _listenerCancelled;
public delegate void MessageDelegate(string message);
public delegate void MessageDelegate2(string droneLocation);
public delegate void MessageDelegate3(string objectLocation);
private readonly MessageDelegate _messageDelegate;
private readonly MessageDelegate2 _messageDelegate2;
private readonly MessageDelegate3 _messageDelegate3;
private readonly ConcurrentQueue<string> _messageQueue = new ConcurrentQueue<string>();
private readonly ConcurrentQueue<string> _droneLocationQueue = new ConcurrentQueue<string>();
private readonly ConcurrentQueue<string> _objectLocationQueue = new ConcurrentQueue<string>();
private void ListenerWork()
{
AsyncIO.ForceDotNet.Force();
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.200.245:12345");
subSocket.Subscribe("");
while (!_listenerCancelled)
{
string frameString;
if (!subSocket.TryReceiveFrameString(out frameString)) continue;
Debug.Log(frameString);
_messageQueue.Enqueue(frameString);
}
subSocket.Close();
}
NetMQConfig.Cleanup();
}
private void ListenerWork2()
{
AsyncIO.ForceDotNet.Force();
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.200.245:12345");
subSocket.Subscribe("");
while (!_listenerCancelled)
{
string frameString2;
if (!subSocket.TryReceiveFrameString(out frameString2)) continue;
Debug.Log(frameString2);
_droneLocationQueue.Enqueue(frameString2);
}
subSocket.Close();
}
NetMQConfig.Cleanup();
}
private void ListenerWork3()
{
AsyncIO.ForceDotNet.Force();
using (var subSocket = new SubscriberSocket())
{
subSocket.Options.ReceiveHighWatermark = 1000;
subSocket.Connect("tcp://192.168.200.245:12345");
subSocket.Subscribe("");
while (!_listenerCancelled)
{
string frameString3;
if (!subSocket.TryReceiveFrameString(out frameString3)) continue;
Debug.Log(frameString3);
_objectLocationQueue.Enqueue(frameString3);
}
subSocket.Close();
}
NetMQConfig.Cleanup();
}
private void Start()
{
//print(raioTerra + " " + longitude);
_netMqListener = new NetMqListener(HandleMessage);
_netMqListener2 = new NetMqListener(HandleDroneLocation);
_netMqListener3 = new NetMqListener(HandleObjectLocation);
_netMqListener.Start();
_netMqListener2.Start();
_netMqListener3.Start();
}
private void HandleMessage(string message)
{
if (LarTarget.name == GameObject.Find("LarTarget").ToString())
{
var splittedStrings = message.Split(' ');
if (splittedStrings.Length != 3) return;
latitude = float.Parse(splittedStrings[0]);
longitude = float.Parse(splittedStrings[1]);
altitude = float.Parse(splittedStrings[2]);
LarTarget.transform.position = new Vector3(latitude, longitude, altitude);
}
else if(objectLocationTarget.name == GameObject.Find("objectLocationTarget").ToString())
{
var splittedStrings = message.Split(' ');
if (splittedStrings.Length != 3) return;
latitude1 = float.Parse(splittedStrings[0]);
longitude1 = float.Parse(splittedStrings[1]);
altitude1 = float.Parse(splittedStrings[2]);
objectLocationTarget.transform.position = new Vector3(latitude1, longitude1, altitude1);
}
else {
var splittedStrings = message.Split(' ');
if (splittedStrings.Length != 3) return;
latitude2 = float.Parse(splittedStrings[0]);
longitude2 = float.Parse(splittedStrings[1]);
altitude2 = float.Parse(splittedStrings[2]);
droneTarget.transform.position = new Vector3(latitude2, longitude2, altitude2);
}
}
private void HandleObjectLocation(string objectLocation)
{
if (objectLocationTarget.name == GameObject.Find("objectLocationTarget").ToString()){
var splittedStrings = objectLocation.Split(' ');
if (splittedStrings.Length != 3) return;
latitude1 = float.Parse(splittedStrings[0]);
longitude1 = float.Parse(splittedStrings[1]);
altitude1 = float.Parse(splittedStrings[2]);
objectLocationTarget.transform.position = new Vector3(latitude1, longitude1, altitude1);
}
else if(LarTarget.name == GameObject.Find("LarTarget").ToString())
{
var splittedStrings = objectLocation.Split(' ');
if (splittedStrings.Length != 3) return;
latitude = float.Parse(splittedStrings[0]);
longitude = float.Parse(splittedStrings[1]);
altitude = float.Parse(splittedStrings[2]);
LarTarget.transform.position = new Vector3(latitude, longitude, altitude);
}
else {
var splittedStrings = objectLocation.Split(' ');
if (splittedStrings.Length != 3) return;
latitude2 = float.Parse(splittedStrings[0]);
longitude2 = float.Parse(splittedStrings[1]);
altitude2 = float.Parse(splittedStrings[2]);
droneTarget.transform.position = new Vector3(latitude2, longitude2, altitude2);
}
}
private void HandleDroneLocation(string droneLocation)
{
if (droneTarget.name == GameObject.Find("droneTarget").ToString()){
var splittedStrings = droneLocation.Split(' ');
if (splittedStrings.Length != 3) return;
latitude2 = float.Parse(splittedStrings[0]);
longitude2 = float.Parse(splittedStrings[1]);
altitude2 = float.Parse(splittedStrings[2]);
droneTarget.transform.position = new Vector3(latitude2, longitude2, altitude2);
}
else if(LarTarget.name == GameObject.Find("LarTarget").ToString())
{
var splittedStrings = droneLocation.Split(' ');
if (splittedStrings.Length != 3) return;
latitude = float.Parse(splittedStrings[0]);
longitude = float.Parse(splittedStrings[1]);
altitude = float.Parse(splittedStrings[2]);
LarTarget.transform.position = new Vector3(latitude, longitude, altitude);
}
else
{
var splittedStrings = droneLocation.Split(' ');
if (splittedStrings.Length != 3) return;
latitude1 = float.Parse(splittedStrings[0]);
longitude1 = float.Parse(splittedStrings[1]);
altitude1 = float.Parse(splittedStrings[2]);
objectLocationTarget.transform.position = new Vector3(latitude1, longitude1, altitude1);
}
}
private void Update()
{
Vector3 coord = calculaPosCoordCam();
Vector3 coord2 = calculaPosCoordCam1();
Vector3 coord3 = calculaPosCoordCam2();
LarTarget.transform.position = coord;
objectLocationTarget.transform.position = coord2;
droneTarget.transform.position = coord3;
//print(coord.x +" " + coord.y + " " + coord.z);
_netMqListener.Update();
_netMqListener2.Update();
_netMqListener3.Update();
}
private void OnDestroy()
{
_netMqListener.Stop();
_netMqListener2.Stop();
_netMqListener3.Stop();
}
private Vector3 calculaPosCoordCam()
{
double dlat = latitude - LocativeGPS.Instance.latitude;
dlat = getCoordEmMetrosDeRaio(raioTerra, dlat);
double dlon = longitude - LocativeGPS.Instance.longitude;
double raioLat = Mathf.Cos((float)latitude) * raioTerra;
dlon = getCoordEmMetrosDeRaio(raioLat, dlon);
double dalt = altitude - 0.0f;// LocativeGPS.Instance.altitude;
return new Vector3((float)dlat, (float)dalt, (float)dlon);
}
private Vector3 calculaPosCoordCam1()
{
double dlat1 = latitude1 - LocativeGPS.Instance.latitude;
dlat1 = getCoordEmMetrosDeRaio(raioTerra, dlat);
double dlon1 = longitude1 - LocativeGPS.Instance.longitude;
double raioLat1 = Mathf.Cos((float)latitude1) * raioTerra;
dlon1 = getCoordEmMetrosDeRaio(raioLat1, dlon1);
double dalt1 = altitude1 - 0.0f;// LocativeGPS.Instance.altitude;
return new Vector3((float)dlat1, (float)dalt1, (float)dlon1);
}
private Vector3 calculaPosCoordCam2()
{
double dlat2 = latitude2 - LocativeGPS.Instance.latitude;
dlat2 = getCoordEmMetrosDeRaio(raioTerra, dlat2);
double dlon2 = longitude2 - LocativeGPS.Instance.longitude;
double raioLat2 = Mathf.Cos((float)latitude2) * raioTerra;
dlon2 = getCoordEmMetrosDeRaio(raioLat2, dlon2);
double dalt2 = altitude2 - 0.0f;// LocativeGPS.Instance.altitude;
return new Vector3((float)dlat2, (float)dalt2, (float)dlon2);
}
private double getCoordEmMetrosDeRaio(double raio, double angulo)
{
double metros = (raio / 180) * Mathf.PI;//
metros *= angulo;
return metros;
}
}
}
I am building a survival shooter, I am using a script that I got from an other project link,the script only spawns the 1st wave and then nothing happens.
It dosent give any warning nor any error
EnemyWave Script
public class WaveManager : MonoBehaviour {
PlayerHealth playerHealth;
public float bufferDistance = 200;
public float timeBetweenWaves = 5f;
public float spawnTime = 3f;
public int startingWave = 1;
public int startingDifficulty = 1;
public Text number;
[HideInInspector]
public int enemiesAlive = 0;
[System.Serializable]
public class Wave {
public Entry[] entries;
[System.Serializable]
public class Entry {
public GameObject enemy;
public int count;
[System.NonSerialized]
public int spawned;
}
}
// All our waves.
public Wave[] waves;
Vector3 spawnPosition = Vector3.zero;
int waveNumber;
float timer;
Wave currentWave;
int spawnedThisWave = 0;
int totalToSpawnForWave;
bool shouldSpawn = false;
int difficulty;
void Start() {
playerHealth = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>();
waveNumber = startingWave > 0 ? startingWave - 1 : 0;
difficulty = startingDifficulty;
StartCoroutine("StartNextWave");
}
void Update() {
if (!shouldSpawn) {
return;
}
if (spawnedThisWave == totalToSpawnForWave && enemiesAlive == 0) {
StartCoroutine("StartNextWave");
return;
}
timer += Time.deltaTime;
if (timer >= spawnTime) {
foreach (Wave.Entry entry in currentWave.entries) {
if (entry.spawned < (entry.count * difficulty)) {
Spawn(entry);
}
}
}
}
IEnumerator StartNextWave() {
shouldSpawn = false;
yield return new WaitForSeconds(timeBetweenWaves);
if (waveNumber == waves.Length) {
waveNumber = 0;
difficulty++;
}
currentWave = waves[waveNumber];
totalToSpawnForWave = 0;
foreach (Wave.Entry entry in currentWave.entries) {
totalToSpawnForWave += (entry.count * difficulty);
}
spawnedThisWave = 0;
shouldSpawn = true;
waveNumber++;
number.text = (waveNumber + ((difficulty - 1) * waves.Length)).ToString();
number.GetComponent<Animation>().Play();
}
void Spawn(Wave.Entry entry) {
timer = 0f;
if (playerHealth.currentHealth <= 0f) {
return;
}
Vector3 randomPosition = Random.insideUnitSphere * 10;
randomPosition.y = 0;
UnityEngine.AI.NavMeshHit hit;
if (!UnityEngine.AI.NavMesh.SamplePosition(randomPosition, out hit, 5, 1)) {
return;
}
spawnPosition = hit.position;
Vector3 screenPos = Camera.main.WorldToScreenPoint(spawnPosition);
if ((screenPos.x > -bufferDistance && screenPos.x < (Screen.width + bufferDistance)) &&
(screenPos.y > -bufferDistance && screenPos.y < (Screen.height + bufferDistance)))
{
return;
}
GameObject enemy = Instantiate(entry.enemy, spawnPosition, Quaternion.identity) as GameObject;
enemy.GetComponent<EnemyHealth>().startingHealth *= difficulty;
enemy.GetComponent<EnemyHealth>().scoreValue *= difficulty;
entry.spawned++;
spawnedThisWave++;
enemiesAlive++;
}}
I'm creating a small C# application to help investigate different designs of Multilayer Perceptron and Radial Basis Function Neural Networks. The MLP is working adequately, but I can't manage to get the RBF Net to work at all.
I've checked and double checked and triple checked the algorithms to see if they match the algorithms that are available online and in papers and books and it seems like they do. I've also checked a colleagues (working) code and compared it to mine to see if there is anything I'd done wrong or left out and found nothing.
So I was hoping some extra eyes and opinions might help me root out the problem, as I've run out of ideas of what to try or where to look. If you want to have a look at or download the entire project you can find it at https://bitbucket.org/floofykh/gameai-coursework
I'll also post here the RBF specific code.
This is the Windows Form which allows the user to input the design of the RBF net and train it.
public partial class RBFForm : Form
{
private const double X_MAX = Math.PI * 2;
private const double X_MIN = 0;
private const double INTERVAL = Math.PI / 90d;
private double m_numPlotPoints;
private double m_noiseValue = 0;
public double StopThreshold { get { return m_stopThreshold; } }
private double m_stopThreshold;
private string m_function = "";
private List<double> m_inputs, m_targets;
private List<RadialBasisFunctionData> m_rbfsData;
private RadialBasisFunctionNetwork m_rbf;
private int m_numRBFs = 1;
private double m_rbfWidth = 1d, m_rbfOffset = 0d, m_rbfSeperation = 0d;
private bool m_changed = true;
private const int testCases = 180;
public RBFForm()
{
InitializeComponent();
ChartArea functionArea = m_functionGraph.ChartAreas.Add("function");
functionArea.AxisX.Maximum = X_MAX;
functionArea.AxisX.Minimum = X_MIN;
functionArea.AxisY.Maximum = 1.5;
functionArea.AxisY.Minimum = -1.5;
ChartArea rbfArea = m_rbfGraph.ChartAreas.Add("RBFs");
rbfArea.AxisX.Maximum = X_MAX;
rbfArea.AxisX.Minimum = X_MIN;
rbfArea.AxisY.Maximum = 1;
rbfArea.AxisY.Minimum = 0;
m_functionGraph.Series.Add("Neural Network");
m_functionGraph.Series.Add("Function");
m_functionGraph.Series.Add("Points");
m_rbfGraph.Series.Add("RBFs");
Neuron.LearningRate = ((double)(m_learningRateSelector).Value);
m_numRBFs = ((int)(m_numRBFsInput).Value);
m_rbfOffset = ((double)(m_rbfOffsetController).Value);
m_rbfSeperation = ((double)(m_rbfOffsetController).Value);
m_rbfWidth = ((double)(m_rbfWidthController).Value);
m_rbf = new RadialBasisFunctionNetwork(this);
}
private void InitialiseFunctionGraph()
{
Series func = m_functionGraph.Series.FindByName("Function");
func.Points.Clear();
func.ChartType = SeriesChartType.Line;
func.Color = Color.Green;
func.BorderWidth = 1;
for (double x = X_MIN; x < X_MAX; x += INTERVAL)
{
double y = 0;
switch (m_function)
{
case "Sin":
y = Math.Sin(x);
break;
case "Cos":
y = Math.Cos(x);
break;
};
func.Points.AddXY(x, y);
}
}
private void InitialiseRBFs()
{
m_rbfsData = new List<RadialBasisFunctionData>();
Series rbfs = m_rbfGraph.Series.FindByName("RBFs");
rbfs.Points.Clear();
rbfs.ChartType = SeriesChartType.Line;
rbfs.Color = Color.IndianRed;
rbfs.BorderWidth = 1;
for(int i=0; i<m_numRBFs; i++)
{
double centre = X_MIN + m_rbfOffset + m_rbfSeperation * i;
RadialBasisFunctionData data = new RadialBasisFunctionData();
data.Centre = centre;
data.Width = m_rbfWidth;
m_rbfsData.Add(data);
DrawRBF(centre, m_rbfWidth, rbfs.Points);
}
}
private void DrawRBF(double centre, double width, DataPointCollection points)
{
if(width > 0)
{
IActivationFunction function = new RadialBasisFunction(centre, width);
for (double x = X_MIN; x < X_MAX; x += INTERVAL)
{
double y = function.Function(x);
points.AddXY(x, y);
}
}
}
private void InitialiseInputPoints()
{
m_inputs = new List<double>();
m_targets = new List<double>();
Series points = m_functionGraph.Series.FindByName("Points");
points.Points.Clear();
points.ChartType = SeriesChartType.Point;
points.Color = Color.Blue;
points.BorderWidth = 1;
double interval = 0d;
if (m_numPlotPoints > 1)
interval = (X_MAX - X_MIN) / (m_numPlotPoints - 1);
for (int point = 0; point < m_numPlotPoints; point++)
{
double x = X_MIN + point * interval;
double y = 0;
switch (m_function)
{
case "Sin":
y = Math.Sin(x);
break;
case "Cos":
y = Math.Cos(x);
break;
};
y += (Program.rand.NextDouble() - 0.5d) * 2d * m_noiseValue;
m_targets.Add(y);
m_inputs.Add(x);
points.Points.AddXY(x, y);
}
}
public void SetNumEpochs(int num)
{
m_numEpochLabel.Text = num.ToString();
}
public void SetNumEpochsAsync(int num)
{
try
{
if (m_numEpochLabel.InvokeRequired)
{
m_numEpochLabel.Invoke((MethodInvoker)delegate
{
m_numEpochLabel.Text = num.ToString();
});
}
}
catch (Exception) { }
}
private void m_rbfSeperationController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
m_rbfSeperation = value;
InitialiseRBFs();
m_changed = true;
}
private void m_numRBFsInput_ValueChanged(object sender, EventArgs e)
{
int value = ((int)((NumericUpDown)sender).Value);
m_numRBFs = value;
InitialiseRBFs();
m_changed = true;
}
private void m_rbfWidthController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
m_rbfWidth = value;
InitialiseRBFs();
m_changed = true;
}
private void m_rbfOffsetController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
m_rbfOffset = value;
InitialiseRBFs();
m_changed = true;
}
private void m_learningRateSelector_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
Neuron.LearningRate = value;
m_changed = true;
}
private void m_momentumController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
Neuron.MomentumAlpha = value;
m_changed = true;
}
private void m_thresholdController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
m_stopThreshold = value;
m_changed = true;
}
private void m_functionSelector_SelectedIndexChanged(object sender, EventArgs e)
{
m_function = ((ComboBox)sender).SelectedItem.ToString();
InitialiseFunctionGraph();
m_changed = true;
}
private void m_plotPointsController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
m_numPlotPoints = value;
InitialiseInputPoints();
m_changed = true;
}
private void m_noiseController_ValueChanged(object sender, EventArgs e)
{
double value = ((double)((NumericUpDown)sender).Value);
m_noiseValue = value;
InitialiseInputPoints();
m_changed = true;
}
private void m_trainButton_Click(object sender, EventArgs e)
{
if (m_rbf != null)
{
if (RadialBasisFunctionNetwork.Running)
{
RadialBasisFunctionNetwork.Running = false;
}
else
{
if (m_changed)
{
m_rbf.Initialise(1, m_rbfsData, 1);
m_changed = false;
}
RadialBasisFunctionNetwork.ErrorStopThreshold = m_stopThreshold;
List<List<double>> inputPatterns = new List<List<double>>();
List<List<double>> targetPatterns = new List<List<double>>();
for (int i = 0; i < m_inputs.Count; i++)
{
List<double> newInputPattern = new List<double>();
newInputPattern.Add(m_inputs[i]);
List<double> newTargetPattern = new List<double>();
newTargetPattern.Add(m_targets[i]);
inputPatterns.Add(newInputPattern);
targetPatterns.Add(newTargetPattern);
}
m_rbf.Train(inputPatterns, targetPatterns);
}
}
}
public void TestAndPresent()
{
List<double> finalData = new List<double>();
for (double x = X_MIN; x < X_MAX; x += INTERVAL)
{
List<double> input = new List<double>();
input.Add(x);
finalData.AddRange(m_rbf.Test(input));
}
PlotNeuralOutput(finalData);
}
public void TestAndPresentAsync()
{
List<double> finalData = new List<double>();
for (double x = X_MIN; x < X_MAX; x += INTERVAL)
{
List<double> input = new List<double>();
input.Add(x);
finalData.AddRange(m_rbf.Test(input));
}
PlotNeuralOutputAsync(finalData);
}
public void PlotNeuralOutput(List<double> output)
{
Series network = m_functionGraph.Series["Neural Network"];
network.Points.Clear();
network.ChartType = SeriesChartType.Line;
network.Color = Color.Red;
network.BorderWidth = 3;
double x = 0;
for (int i = 0; i < output.Count; i++)
{
network.Points.AddXY(x, output[i]);
x += INTERVAL;
}
}
public void PlotNeuralOutputAsync(List<double> output)
{
try
{
if (m_functionGraph.InvokeRequired)
{
m_functionGraph.Invoke((MethodInvoker)delegate
{
Series network = m_functionGraph.Series["Neural Network"];
network.Points.Clear();
network.ChartType = SeriesChartType.Line;
network.Color = Color.Red;
network.BorderWidth = 3;
double x = 0;
for (int i = 0; i < output.Count; i++)
{
network.Points.AddXY(x, output[i]);
x += INTERVAL;
}
});
}
}
catch (Exception) { }
}
}
Here is the RadialBasisFunction class where most of the RBF algorithm takes place, specificaly in FeedForward().
class RadialBasisFunctionNetwork
{
private NeuronLayer m_inputLayer;
private NeuronLayer m_radialFunctions;
private NeuronLayer m_outputLayer;
private int m_numRadialFunctions = 0;
public static bool Running = false;
public static double ErrorStopThreshold {get; set;}
private static int m_epoch = 0;
public static int Epoch { get { return m_epoch; } }
private RBFForm m_RBFForm = null;
public RadialBasisFunctionNetwork(RBFForm RBFForm)
{
m_RBFForm = RBFForm;
m_inputLayer = new NeuronLayer();
m_radialFunctions = new NeuronLayer();
m_outputLayer = new NeuronLayer();
}
public void Initialise(int numInputs, List<RadialBasisFunctionData> radialFunctions, int numOutputs)
{
ErrorStopThreshold = 0d;
m_epoch = 0;
m_numRadialFunctions = radialFunctions.Count;
m_inputLayer.Neurons.Clear();
//Add bias neuron
/*Neuron inputBiasNeuron = new Neuron(1d);
inputBiasNeuron.Initialise(m_numRadialFunctions);
m_inputLayer.Neurons.Add(inputBiasNeuron);*/
for(int i=0; i<numInputs; i++)
{
Neuron newNeuron = new Neuron();
newNeuron.Initialise(m_numRadialFunctions);
m_inputLayer.Neurons.Add(newNeuron);
}
m_outputLayer.Neurons.Clear();
for (int i = 0; i < numOutputs; i++)
{
Neuron newNeuron = new Neuron();
m_outputLayer.Neurons.Add(newNeuron);
}
m_radialFunctions.Neurons.Clear();
//Add bias neuron
/* Neuron outputBiasNeuron = new Neuron(1d);
outputBiasNeuron.Initialise(numOutputs);
outputBiasNeuron.ActivationFunction = new ConstantActivationFunction();
m_radialFunctions.Neurons.Add(outputBiasNeuron);*/
for (int i = 0; i < m_numRadialFunctions; i++)
{
Neuron newNeuron = new Neuron();
newNeuron.Initialise(numOutputs);
newNeuron.ActivationFunction = new RadialBasisFunction(radialFunctions[i].Centre, radialFunctions[i].Width);
m_radialFunctions.Neurons.Add(newNeuron);
}
}
public void Train(List<List<double>> inputs, List<List<double>> targets)
{
Running = true;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
while (Running)
{
TrainPatterns(inputs, targets);
m_RBFForm.SetNumEpochsAsync(m_epoch);
m_RBFForm.TestAndPresentAsync();
}
});
bw.RunWorkerAsync();
}
private void TrainPatterns(List<List<double>> inputs, List<List<double>> targets)
{
Queue<int> randomIndices = GenRandomNonRepNumbers(inputs.Count, 0, inputs.Count, Program.rand);
bool trained = true;
while(randomIndices.Count > 0)
{
int index = randomIndices.Dequeue();
TrainPattern(inputs[index], targets[index]);
foreach(Neuron neuron in m_outputLayer.Neurons)
{
if (Math.Abs(neuron.Error) > ErrorStopThreshold)
trained = false;
}
}
m_epoch++;
if (trained)
Running = false;
}
public void TrainPattern(List<double> inputs, List<double> targets)
{
InitialisePatternSet(inputs, targets);
FeedForward();
}
public List<double> Test(List<double> inputs)
{
InitialisePatternSet(inputs, null);
FeedForward();
return GetOutput();
}
public void FeedForward()
{
//Feed from input
for(int i=0; i<m_radialFunctions.NumNeurons; i++)
{
Neuron radialFunctionNeuron = m_radialFunctions.Neurons[i];
radialFunctionNeuron.Output = 0d;
for(int j=0; j<m_inputLayer.NumNeurons; j++)
{
Neuron inputNeuron = m_inputLayer.Neurons[j];
radialFunctionNeuron.Output += radialFunctionNeuron.ActivationFunction.Function(inputNeuron.Output);
}
}
//Feed to output
for (int i = 0; i < m_outputLayer.NumNeurons; i++)
{
Neuron outputNeuron = m_outputLayer.Neurons[i];
outputNeuron.Output = 0d;
for (int j = 0; j < m_radialFunctions.NumNeurons; j++)
{
Neuron radialFunctionNeuron = m_radialFunctions.Neurons[j];
outputNeuron.Output += radialFunctionNeuron.Weight(i) * radialFunctionNeuron.Output;
}
outputNeuron.Error = (outputNeuron.Target - outputNeuron.Output);
}
//Update weights
for (int i = 0; i < m_radialFunctions.NumNeurons; i++)
{
Neuron radialFunctionNeuron = m_radialFunctions.Neurons[i];
for (int j = 0; j < m_outputLayer.NumNeurons; j++)
{
Neuron outputNeuron = m_outputLayer.Neurons[j];
if(Math.Abs(outputNeuron.Error) > m_RBFForm.StopThreshold)
radialFunctionNeuron.m_weights[j] += Neuron.LearningRate * outputNeuron.Error * radialFunctionNeuron.Output;
}
}
}
public List<double> GetOutput()
{
List<double> output = new List<double>();
for (int i = 0; i < m_outputLayer.NumNeurons; i++)
{
output.Add(m_outputLayer.Neurons[i].Output);
}
return output;
}
private void InitialisePatternSet(List<double> inputs, List<double> targets)
{
m_inputLayer.SetInputs(inputs, false);
if(targets != null)
{
m_outputLayer.SetTargets(targets);
}
}
private Queue<int> GenRandomNonRepNumbers(int num, int min, int max, Random generator)
{
if (max - min < num)
return null;
Queue<int> numbers = new Queue<int>(num);
for (int i = 0; i < num; i++)
{
int randNum = 0;
do
{
randNum = generator.Next(min, max);
} while (numbers.Contains(randNum));
numbers.Enqueue(randNum);
}
return numbers;
}
}
This is the Radial Basis Function I am using as an activation function
class RadialBasisFunction : IActivationFunction
{
private double m_centre = 0d, m_width = 0d;
public RadialBasisFunction(double centre, double width)
{
m_centre = centre;
m_width = width;
}
double IActivationFunction.Function(double activation)
{
double dist = activation - m_centre;
return Math.Exp(-(dist * dist) / (2 * m_width * m_width));
//return Math.Exp(-Math.Pow(dist / (2 * m_width), 2d));
//return Math.Exp(-Math.Pow(dist, 2d));
}
}
The NeuronLayer class is really just a wrapper around a List of Neurons, and isn't entirely necessary anymore, but I've been focussing on getting everything working rather than keeping my code clean and well designed.
class NeuronLayer
{
public int NumNeurons { get { return Neurons.Count; } }
public List<Neuron> Neurons { get; set; }
public NeuronLayer ()
{
Neurons = new List<Neuron>();
}
public void SetInputs(List<double> inputs, bool skipBias)
{
for (int i = 0; i < Neurons.Count; i++)
{
if(skipBias)
{
if (i != 0)
Neurons[i].Input = inputs[i-1];
}
else
{
Neurons[i].Input = inputs[i];
}
}
}
public void SetTargets(List<double> targets)
{
for (int i = 0; i < Neurons.Count; i++)
{
Neurons[i].Target = targets[i];
}
}
}
And finally the Neuron class. This class was made while I was coding the MLP and while I was still trying to figure out exactly how Neural Nets work. So unfortunately a lot of the code in it is specific to MLPs. I hope to change this once I've got everything working and can start cleaning everything and make the application more user-friendly. I'm going to add all the functions for completeness, but I've checked and double checked and I shouldn't be using any of the MLP specific code of Neuron anywhere in my RBF network. The MLP specific stuff is WithinThreshold, and all the functions after Weight(int).
class Neuron
{
private IActivationFunction m_activationFunction = null;
public IActivationFunction ActivationFunction { get { return m_activationFunction; } set { m_activationFunction = value; } }
public double Input { get { return Output; } set { Output = value; } }
public double Output { get; set; }
public double Error { get; set; }
public double Target { get; set; }
private double m_activation = 0d;
public bool WithinThreshold { get { return Math.Abs(Error) < MultilayerPerceptron.ErrorStopThreshold; } }
public static double LearningRate { get; set; }
public static double MomentumAlpha { get; set; }
public List<double> m_weights;
private List<double> m_deltaWeights;
public Neuron()
{
Output = 0d;
m_weights = new List<double>();
m_deltaWeights = new List<double>();
m_activationFunction = new TanHActFunction();
}
public Neuron(double input)
{
Input = input;
Output = input;
m_weights = new List<double>();
m_deltaWeights = new List<double>();
m_activationFunction = new TanHActFunction();
}
public void Initialise(int numWeights)
{
for(int i=0; i<numWeights; i++)
{
m_weights.Add(Program.rand.NextDouble()*2d - 1d);
}
}
public double Weight(int index)
{
if (m_weights != null && m_weights.Count > index)
return m_weights[index];
return 0d;
}
public void Feed(NeuronLayer layer, int neuronIndex)
{
List<Neuron> inputNeurons = layer.Neurons;
m_activation = 0;
for (int j = 0; j < layer.NumNeurons; j++)
{
m_activation += inputNeurons[j].Output * inputNeurons[j].Weight(neuronIndex);
}
Output = m_activationFunction.Function(m_activation);
}
public void CalculateError(NeuronLayer successor, bool outputLayer)
{
if(outputLayer)
{
Error = (Target - Output) * ActivationFunction.FunctionDeriv(Output);
}
else
{
Error = 0d;
for(int i=0; i<successor.NumNeurons; i++)
{
Neuron neuron = successor.Neurons[i];
Error += (neuron.Error * m_weights[i] * ActivationFunction.FunctionDeriv(Output));
}
}
}
public void UpdateWeights(NeuronLayer successor)
{
if (MomentumAlpha != 0)
{
for (int i = 0; i < successor.NumNeurons; i++)
{
var neuron = successor.Neurons[i];
if (m_deltaWeights.Count <= i)
{
double deltaWeight = LearningRate * neuron.Error * Output;
m_weights[i] += deltaWeight;
m_deltaWeights.Add(deltaWeight);
}
else
{
double deltaWeight = /*(1 - MomentumAlpha)*/LearningRate * neuron.Error * Output + MomentumAlpha * m_deltaWeights[i];
m_weights[i] += deltaWeight;
m_deltaWeights[i] = deltaWeight;
}
}
}
else
{
for (int i = 0; i < successor.NumNeurons; i++)
{
var neuron = successor.Neurons[i];
double deltaWeight = LearningRate * neuron.Error * Output;
m_weights[i] += deltaWeight;
}
}
}
}
I hope some extra eyes and opinions helps find my problem.
PS If you do download the source code from the repository and try run the application, please be aware that it will break if you don't set all necessary values before training, or if you press the reset button. I should get rid of the reset button, but I haven't yet. Sorry!
I found where the problem was.
I was updating the weights inside the FeedForward method. However, that method is called both when training and testing the network. So I was updating weights when I shouldn't have been, while testing the network.