Storing variables of GameObjects into Array [Unity] - arrays

I have 3 kinds of GameObject, namely blueBook, redBook and greenBook. There are 2 blueBook, 7 redBook and 4 greenBook in the scene.
They are each assigned with the following example script that have 3 properties.
public class blueBook : MonoBehaviour {
public string type = "BlueBook";
public string colour = "Blue";
public float weight;
float s;
void Start () {
float weightValue;
weightValue = Random.value;
weight = Mathf.RoundToInt (700*weightValue+300);
s=weight/1000; //s is scale ratio
transform.localScale += new Vector3(s,s,s);
}
// Update is called once per frame
void Update () {
}
}
In the new class, I want to take all the variables of the GameObject (type, colour, weight) and store them inside an array. How to do this?
After they are all stored inside the array, user will input an weight. Then another class will search through all the info to delete both the array and GameObject(in the scene) with the same amount of weight.
Thank you.
UPDATE
blueBook.cs
public class blueBook: MonoBehaviour {
public string type = "blueBook";
public string colour = "Red";
public float weight;
float s;
void Start () {
float weightValue;
weightValue = Random.value;
weight = Mathf.RoundToInt (500*weightValue+100);
s=weight/1000; //s is scale ratio
transform.localScale += new Vector3(s,s,s);
Debug.Log(weight);
}
// Update is called once per frame
void Update () {
}
}
block.cs
public class block: MonoBehaviour{
public List<GameObject> players;
void Start()
{ Debug.Log(players[1].GetComponent<blueBoook>().weight);
}
// Update is called once per frame
void Update () {
}
The debug.log for block.cs displayed 0 everytime eventho it display otherwise in debug.log of bluebook.cs. It is because it displayed the initial number? I don know wat is wrong

For all blocks in one list you can create a script that has a public list and you drag all your gameobjects into the list in the inspector.
using System.Collections.Generic;
public class ObjectHolder : MonoBehaviour
{
public List<GameObject> theBooks;
// You can remove by weight e.g. like this
public void DeleteByWeight(float inputWeight)
{
for(int i = theBooks.Count - 1; i >= 0; i--)
{
if(theBooks[i].GetComponent<Book>().weight == inputWeight)
Destroy(theBooks[i]);
theBooks.RemoveAt(i);
}
}
}
}
The script on the blocks needs to be renamed to the same name for all (Book in my example). From your code that is no problem since they only differ in the value of the members.

Related

Calculate difference in property

I have converted a list of JSON objects to a generic list.
The Data structure on the items is as following
public class Person
{
private string Name;
private int Age;
private string Weightloss;
}
The Weightloss string is of type "109-102" and I need to calculate how much each person has lost in weight since they signed up. I my examlpe it'd be 7. How to I, using LINQ Method syntax, calculate each weight loss (or gain). I assume I'll need to split up the string but I'm not really sure how
Rather odd question, but if Linq is what you want, here is how one can go about it:
Create a function inside your class to calculate the weight difference:
public class Person
{
//Constructor
public Person(string name, int age, string weightLoss)
{
Name = name;
Age = age;
Weightloss = weightLoss;
}
public string Name;
private int Age;
private string Weightloss;
/// <summary>
/// Calculates the weight difference from the WeightLoss property.
/// </summary>
/// <returns></returns>
public int GetWeightLoss()
{
//Get the values
var parts = Weightloss.Split('-')
.Select(value => Convert.ToInt32(value))
.ToArray();
//Calculate the difference
var difference = parts[0] - parts[1];
return difference;
}
}
Not clean and I personally dislike it but it's homework so...
I added a constructor for initialization and changed the Name field to public so you can output it:
var list = new List<Person>()
{
new Person("Juan", 30, "109-102"),
new Person("Max", 35, "119-103"),
new Person("John", 40, "109-105"),
};
//Figure out the largest loss
var maxLossPerson = list.OrderByDescending(p => p.GetWeightLoss()).First();
Console.WriteLine($"{maxLossPerson.Name} lost the most with {maxLossPerson.GetWeightLoss()} pound(s)");
Output:
Max lost the most with 16 pound(s)
You're either going to use a string split or a regular expression.
Assuming your string is always formatted "Weight1-Weight2", a string split would be fairly simple:
public int[] ParseWeights(string weightString) {
var weights = weightString.Split('-');
var beginningWeight = Convert.ToInt32(weights[0]);
var endingWeight = Convert.ToInt32(weights[1]);
return new int[] {beginningWeight, endingWeight};
}
Add another property to Person:
public class Person
{
private string Name;
private int Age;
private string Weightloss;
public int WeightLost
{
get
{
int[] values = Weightloss.Split('-').Select(i => int.Parse(i)).ToArray();
return values[0] - values[1];
}
}
}
If you look for a even more Linq way, you can use the follow way:
private string Weightloss;
public int WeightLossInt => Weightloss
.Split('-')
.Select((value, index) => index == 0 ? int.Parse(value) : -int.Parse(value))
.Sum();
}

Unity prefab array instantiate and destroy

I am having a very little problem in my Unity project but can't find a proper help or way to do. I am stuck at point where I have an array of prefab GameObjects and I am trying to instantiate index 1 GameObject and when it destroyed instantiate the next index. Here is how I am doing it. I have two scripts: One to instantiate and other one to destroy it.
Scripts 1:
public class GameObjectsArray : MonoBehaviour {
public static GameObjectsArray Instance { get; set; }
public GameObject[] Objects;
public int i=0;
// Use this for initialization
void Start()
{
InstiatingMethod();
//Instantiate(Objects[i]);
}
public void InstiatingMethod()
{
Instantiate(Objects[i]);
}
}
Scripts 2:
public class CheckDestroy : MonoBehaviour {
//public GameObject[] Objects;
//int i;
// Use this for initialization
void Start () {
Debug.Log("executed");
//Objects = GameObject.FindGameObjectsWithTag("Player");
//OnMouseDown();
//Instantiate(Objects[i], transform.position, transform.rotation);
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
BoxCollider boxCollider = hit.collider as BoxCollider;
if (boxCollider != null)
{
GameObjectsArray.Instance.i++;
GameObjectsArray.Instance.InstiatingMethod();
Destroy(boxCollider.gameObject);
}
}
}
}
}
So I created a very quick project to make a good response:
Scene Image
In the scene, we will have an empty game object that will contain our script that I called "GameManager", basically this script will do everything, it's more logic to put your logic in one script.
public GameObject[] GameObjects;
private int _targetIndex = -1;
private RaycastHit _hit;
private void Start()
{
InstantiateNextGameObject();
}
public void InstantiateNextGameObject()
{
//if the index is pointing at the last game object in the array, init the index to -1
if (_targetIndex == GameObjects.Length - 1)
_targetIndex = -1;
Instantiate(GameObjects[++_targetIndex]);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out _hit))
{
BoxCollider boxCollider = _hit.collider as BoxCollider;
if (boxCollider != null)
{
InstantiateNextGameObject();
Destroy(boxCollider.gameObject);
}
}
}
}
we will have an array of gameobjects following with the targetIndex which will start from -1.
The function InstantiateNextGameObject() will simply increment targetIndex and then instantiate a gameobject from the array (++targetIndex the first time will be 0, second time 1 etc). We have to check also if the targetIndex reaches the end of the array, put it back to -1.
Then basically what you did in the update, when you click on a gameobject, instantiate the next one and destroy the current.
At the end, you will get something like that:
https://ayoub-gharbi.org/youba_docs/stackoverflow/stackoverflow01.mp4
Feel free to ask me if you didn't understand anything:)
Happy coding!

Allowing User to Select multiple items in a GridView

Very new to coding through Android with no knowledge of Java watsoever. I've been putting together pieces through other questions posted but I'm struggling.
I created an array called 'images2' at the top of my OnCreate method and put a bunch of colors from my drawable into it, one by one. That part works great but I've been trying to create an onClickListner that has an OnClick method that changes the drawable when you click on it to another color. I want them all to change to the same color. I know that I can set the selector programmatically: gridview2.setSelector(new ColorDrawable(Color.BLACK)); but change the selector, either in the backend or XMl code doesn't help me get the new drawable to stick. So I created another listArray in the adapter and I can call it in the main. I have an index in the onClick that will go through all 25 possible item positions and I want to make it so that it will change the drawable to each position that is in the array. It also adds the current position clicked into the array myarray.add(position); but I just realized that value might not be being saved. The arrayList is declared public but it is declared public within the adapter so do changes in the OnCreate have no effect? I'm sorry. THAT is definitely a noobinoob-noob question.
/**
* Created by Jordan on 3/25/2017.
*/
public class Welcome extends AppCompatActivity implements AdapterView.OnItemClickListener {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome);
final List<Integer> images2 = new ArrayList<Integer>();
images2.add(R.drawable.grid1);images2.add(R.drawable.grid6);
images2.add(R.drawable.grid2);images2.add(R.drawable.grid2);
images2.add(R.drawable.grid3);images2.add(R.drawable.grid1);
images2.add(R.drawable.grid4);images2.add(R.drawable.grid3);
images2.add(R.drawable.grid5);images2.add(R.drawable.grid2);
images2.add(R.drawable.grid6);images2.add(R.drawable.grid6);
images2.add(R.drawable.open);images2.add(R.drawable.grid4);
images2.add(R.drawable.grid1);images2.add(R.drawable.grid1);
images2.add(R.drawable.grid6);images2.add(R.drawable.grid4);
images2.add(R.drawable.grid4);images2.add(R.drawable.grid2);
images2.add(R.drawable.grid3);images2.add(R.drawable.grid3);
images2.add(R.drawable.grid6);images2.add(R.drawable.grid1);
images2.add(R.drawable.grid5);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final GridView gridview2 = (GridView) findViewById(R.id.welcomeGrid);
final Welcome.ImageAdapter mAdapter = new Welcome.ImageAdapter(this, images2);
gridview2.setAdapter(mAdapter);
gridview2.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE);
gridview2.setItemChecked(2, true);
gridview2.setOnItemClickListener(this);
gridview2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// ArrayList<Integer> clickedStatus = new ArrayList<Integer>();
ArrayList<Integer> clickedStatus = new ArrayList<>(25);
clickedStatus.add(position);
if (position == 12){
setContentView(R.layout.login);
}
else if(position != 12) {
// no matter, whether the item has already been clicked or not I want this toast to pop up to promp the user to actually enter the app and sign in
Toast.makeText(Welcome.this, "You selected " + position+ ".. Please select middle tile to enter!",
Toast.LENGTH_SHORT).show();
if(clickedStatus.contains(position)){
// as soon as it's noticed that the an integer matching the current position is currently stored in the
// array list (clickedStatus), I want it removed right below
// was passing item in place of position into the remove(). Don't know why Integer item = (Integer) parent.getItemAtPosition(position);
//I want to go through 25 numbers and
for(int i=0; i<25;i++ ){
// compare those ints to what is in contained in the clickedstatus
if(clickedStatus.contains(i)){
// Drawable Marker = getResources().getDrawable(R.drawable.celeb1);
images2.set(i, R.drawable.celeb1);
//for every int that is stored in click status I want
// to call the item and change the background of that item to a specified drawable file.
}
}
}
else {
clickedStatus.add(position);
// images2.set(position, );
for(int i=1; i<25;i++ ){
// compare those ints to what is in contained in the clickedstatus
if(clickedStatus.contains(i)){
// Drawable Marker = getResources().getDrawable(R.drawable.celeb1);
images2.set(i, R.drawable.celeb1);
//for every int that is stored in click status I want
// to call the item and change the background of that item to a specified drawable file.
}
}
}
// gridview2.setSelector(new ColorDrawable(Color.BLACK));
// mAdapter.notifyDataSetChanged();
}
}
}
);
}
// I think this got generated automatically at some point somehow. Might of been with the multichoicemode line above ^
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
//IMAGES ARE REFERENCED HERE V---
private List<Integer> mImages2;
public ArrayList<Integer> clickedStatus = new ArrayList<Integer>();
//create array to store whether an item has been clicked or not. needs to be public!!
//check to determine the case in the below method
// IGNORE THIS
// private int selectedPosition = -1;
//public void setSelectedPosition(int position) {
// selectedPosition = position;
//}
public ImageAdapter( final Context c, final List<Integer> images2){
mContext = c;
mImages2 = images2;
}
public int getCount() {
return mImages2.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return 1;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(140, 120));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 0, 0, 0);
} else {
imageView = (ImageView) convertView;
}
if(clickedStatus.contains(position)){
convertView.setSelected(true);
convertView.setPressed(true);
convertView.setBackgroundColor(Color.GREEN);
}
imageView.setImageResource(mImages2.get(position));
return imageView;
}
;}
}
I created and finalized a different set of Arrays for holding every possible five combinations of selections that would result in a win. Titled Diagonal (1, 2, 3, 4, 5), Horizontal(1, 2, 3, 4, 5) , Vertical (1, 2, 3, 4, 5), etc. Upon click a value is stored at the appropriate position of the ListArray and I have relative checks (if statements) that loops everytime the button is click. Does not slow the app down substantially, looks ugly on paper but is very functional without the use of checkboxes. If anybody is interested in seeing the code they may comment.

Accessing a variable in another scene

Is it possible to change a variable in another scene in unity. I have a script right now that has the user pick 5 heroes and those 5 heroes get saved to a array, but in order for the game to run how i want it, that array will be in another scene and I'm not sure how to go about saving the five heroes data to an array in another scene. I can do it all in one scene but 2 scenes would be more efficient. Here's my code:
using UnityEngine;
using System.Collections;
public class HeroChooser : MonoBehaviour {
public static GameObject Archer;
GameObject Berserker;
GameObject Rouge;
GameObject Warrior;
GameObject Mage;
GameObject MainCamera;
public int counter = 0;
public bool archerOn = false;
public bool berserkerOn = false;
public bool rougeOn = false;
public bool mageOn = false;
public bool warriorOn = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnGUI(){
if(archerOn == false){
if (GUI.Button (new Rect(50,0,50,50), "Archer")){
Archer = GameObject.Find("Archer");
MainCamera = GameObject.Find("Main Camera");
HeroArraySaver heroArraySaver = MainCamera.GetComponent<HeroArraySaver>();
heroArraySaver.array[counter] = Archer;
archerOn = true;
counter++;
}
}
Its saying that: Static member HeroArraySaver.array cannot be accessed with an instance reference, qualify it with a type name instead im not sure how to go about fixing it.
A simple way would be to create an empty GameObject and attach a script/MonoBehaviour to that which holds your data. To make it persist you would have to call DontDestroyOnLoad() on that GameObject. This will ensure your GameObject will hang around when moving to a different scene.
So something like:
GameObject myPersistentDataObject = new GameObject("myPersistentDataObject");
MyDataClass data_class = myPersistentDataObject.AddComponent<MyDataClass>();
//set your data to whatever you need to maintain
And in your Awake of your MyDataClass you'd do something like
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
Then in your other scene you can simply find your GameObject again and retrieve its data from the attached component.
Assuming you have integer IDs for the heroes, simply store them in a static variable:
public class GlobalData {
public static int[] heroIds;
}
Static variables can be accessed from any scene and will persist as long as your game runs. The same technique works for strings or enums.

Using Sencha GXT 3, generate a line chart populated with a dynamic number of line series fields?

Using Sencha GXT 3.0 is it possible to generate a line chart and populate it with a dynamic number of line series fields, and if so, what is the recommended method?
I know multiple series fields can be added to a chart, but the line chart examples (and the other chart examples for that matter) make use of an interface which extends PropertyAccess<?> and the interface specifies a static number of expected fields (e.g. data1(), data2(), data3(), etc.). If the interface is to be used to specify the fields to add to the chart, how could you account for a chart which may require n number of fields (i.e. n number of line series on a given chart).
Example provided on Sencha's site:
http://www.sencha.com/examples/#ExamplePlace:linechart
I ran into the same issue. It would be a much nicer design if each series had a store instead of having one store per chart.
I had one long list of metric values in metricDataStore. Each metric value has a description. I wanted all the metric values with the same description displayed on one (and only one) series. I had my value providers for each series return null for both the x and y axis if the value wasn't supposed to be in the series.
This seems like a hack to me but it works for my usage:
myChart = new Chart<MetricData>();
myChart.setStore(metricDataStore);
.
.
.
for (MetricInfo info : metricInfoData) {
LineSeries<MetricData> series = new LineSeries<MetricData>();
series.setChart(myChart);
series.setSmooth(false);
series.setShownInLegend(true);
series.setHighlighting(true);
series.setYAxisPosition(Chart.Position.LEFT);
series.setYField(new MetricValueProvider(info.getName()));
series.setXAxisPosition(Chart.Position.BOTTOM);
series.setXField(new MetricTimeProvider(info.getName()));
myChart.addSeries(series);
}
.
.
.
private class MetricTimeProvider extends Object implements ValueProvider<MetricData, Long> {
private String metricName;
public MetricTimeProvider(String metricName) {
this.metricName = metricName;
}
#Override
public Long getValue(MetricData m) {
if (metricName != null && metricName.equals(m.getLongDesc()))
return m.getId();
else
return null;
}
#Override
public void setValue(MetricData m, Long value) {
}
#Override
public String getPath() {
return null;
}
}
private class MetricValueProvider extends Object implements ValueProvider<MetricData, Double> {
private String metricName;
public MetricValueProvider(String metricName) {
this.metricName = metricName;
}
#Override
public Double getValue(MetricData m) {
if (metricName != null && metricName.equals(m.getLongDesc()))
return m.getMetricValue();
else
return null;
}
#Override
public void setValue(MetricData m, Double value) {
}
#Override
public String getPath() {
return null;
}
}

Resources