Creating a "Chain Reaction" of colliders or triggers in Unity 2D - arrays

I'm trying to create a 'Chain Reaction" of sorts. What I mean is that I have a bool on all of my game objects. When Object A's bool is set to true during gameplay, I would like object B to be set to true and then C and so on for every game object that is in the chain. It should also work the other way around, so that if A is set to false again, all of the objects in the 'chain' are set to false.
I currently have a system where I add each currently colliding object to a list of gameObjects. But I have no idea how to create this 'knock on' effect where one object affects all of the objects in the chain.
Is there a simpler way of achieving this?

What you show above can be described as a node, where each node has a child node (or nodes) and a parent node.
public class Node
{
public Node parentNode;
public Node childNode;
public bool someBool;
}
Then you can use a recursive function to traverse the nodes. Below is an example of traversal utilizing the child nodes.
public void SetBoolOnChildNodes(Node rootNode, bool value)
{
if (rootNode != null)
{
rootNode.someBool = value;
SetBoolOnChildNodes(rootNode.childNode, value);
}
}
If order is not important, it would make sense to have the root object hold a list of all nodes and have each node hold reference to the root object. Then you just set the boolean value using a loop constructed from the root objects node list.
public class Node2
{
public Node2 rootNode; // Null for root node, populated for all others
public List<Node2> nodes; // Populated only on root node (or all.. doesnt really matter other than memory)
public bool someBool;
}
public void SetValueOnChildNodes(Node2 rootNode, bool value)
{
if (rootNode == null) return;
rootNode.someBool = value;
foreach (var node in rootNode.nodes)
{
node.someBool = value;
}
}

Related

How to open a file by clicking on it in TreeView

How do I open a file (ex. PDF) when I click the lowest child node in my tree.
I have created a TreeView program which is automatically filled by a database file.
Associate a path to that node, then use something like this:
private void LinkClicked(object sender, LinkClickedEventArgs e)
{
Process.Start(#".\" + "YOUR FILE NAME AND EXTENSION");
}
Read about: Process.Start
Starts a process resource by specifying the name of a document or application
file and associates the resource with a new System.Diagnostics.Process component.
You need to look at TreeNode Class
Example :
private void Form1_Load(object sender, EventArgs e)
{
//
// This is the first node in the view.
//
TreeNode treeNode = new TreeNode("Windows");
treeView1.Nodes.Add(treeNode);
//
// Another node following the first node.
//
treeNode = new TreeNode("Linux");
treeView1.Nodes.Add(treeNode);
//
// Create two child nodes and put them in an array.
// ... Add the third node, and specify these as its children.
//
TreeNode node2 = new TreeNode("C#");
TreeNode node3 = new TreeNode("VB.NET");
TreeNode[] array = new TreeNode[] { node2, node3 };
//
// Final node.
//
treeNode = new TreeNode("Dot Net Perls", array);
treeView1.Nodes.Add(treeNode);
}
Though example is not reading nodes from DB. You can do that writing a query to fetch nodes.Follow steps on following path , it will lead you from scratch
Create a TreeView from a Database in Windows Forms and C#
Example Source : Tree View
For opening file on Node click look at
public event TreeNodeMouseClickEventHandler NodeMouseClick
// If a node is double-clicked, open the file indicated by the TreeNode.
void treeView1_NodeMouseClick(object sender,
TreeNodeMouseClickEventArgs e)
{
try
{
System.Diagnostics.Process.Start(#"c:\" + e.Node.Text);//e.Node.Text contains fileName
}
// If the file is not found, handle the exception and inform the user.
catch (System.ComponentModel.Win32Exception)
{
MessageBox.Show("File not found.");
}

Objectify - save order of Ref<?>-s

I have a system where I'm trying to minimize the number of Datastore writes (who wouldn't?), all the while using ancestor relations. Consider the following simplified classes:
public class Ancestor {
#Id
private String id;
private String field;
private Ref<Descendant> descendantRef;
public Descendant getDescendant() {
return this.descendantRef.get();
}
public void setDescendant(Descendant des) {
this.descendantRef = Ref.create(des);
}
}
public class Descendant {
#Id
private String id;
private String field;
#Parent
private Key parent;
}
My problem: even though I set the descendant ref, upon saving the Ancestor entity, a null is saved, but if I save the Descendant as well, Objectify complains Attempted to save a null entity.
My question: I gathered that Objectify optimizes the order of get() operations with the #Load annotation, so is there a way to make it do the same on save() operations as well, so that by the time the Ancestor is being sent to the Datastore, the Descendant ref is populated properly?
Thank you in advance for any advice!
You can hide this implementation like this:
public Descendant getDescendant() {
// You probably don't want to break your code on null descendantRef
if (this.descendantRef != null) {
return this.descendantRef.get();
}
return null;
}
public void setDescendant(Descendant des) {
// Insert if this des have never been insert
if (getDescendant() != null) {
new DescendantEndpoint().insert(des);
}
// You probably don't want to break your code on null des
if (des != null) {
this.descendantRef = Ref.create(des);
}
}
By this, you don't have to do deal with each insertion of the ref on each endpoint you will make. Still, this method is not optimized for bulk insert as it will insert on each seperate datastore connection.
For this you can do something like this:
private Object bulkInsertAncestor(ArrayList<Ancestor> list){
ArrayList<Descendant> descendantArrayList = //get descendant list
// You should do all this inside a transaction
new DescendantEndpoint().bulkInsertDescendant(descendantArrayList);
return ofy().save().entities(list);
}
Objectify only complains that you Attempted to save a null entity if you literally pass a null value to the save() method.
This isn't an order-of-operations issue. FWIW, neither Objectify nor the underlying datastore provides any kind of referential integrity checks. It does not matter which you save first.

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.

Sort ListCollectionView from second item down

In an MVVM environment, I have a ListCollectionView bound to an ObservableCollection. My Foo objects have a IsDefault property to them, and my requirement is to have that item first in the list, and the rest should be alpha-sorted.
So this code only sorts the whole list, obviously:
_list = new ListCollectionView(Model.Data);
_list.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
Not sure how to make sure that item #3 (for example, which has IsDefault=true) be at the top of the list, and the rest (that have IsDefault=false) be alpha sorted.
Is this a case to use _list.CustomSort and implement IComparer in some way?
Yes, this is exactly the case where you need to use ListCollectionView.CustomSort. Custom sorting is mutually exclusive with using SortDescriptions; the documentation for the former is explicit about this:
Setting this property clears a previously set SortDescriptions value.
So what you need to do is define an IComparer and use it to sort the view:
class CustomComparer : IComparer
{
public int Compare (object lhs, object rhs)
{
// missing: checks for null, casting to Model.Data, etc etc
if (lhsModelData.IsDefault && rhsModelData.IsDefault) {
return lhsModelData.Name.CompareTo(rhsModelData.Name);
}
else if (lhsModelData.IsDefault) {
return -1;
}
else if (rhsModelData.IsDefault) {
return 1;
}
else {
return lhsModelData.Name.CompareTo(rhsModelData.Name);
}
}
}

Restoring exact scroll position of a listbox in Windows Phone 7

I'm working on making an app come back nicely from being tombstoned. The app contains large listboxes, so I'd ideally like to scroll back to wherever the user was while they were scrolling around those listboxes.
It's easy to jump back to a particular SelectedItem - unfortunately for me, my app never needs the user to actually select an item, they're just scrolling through them. What I really want is some sort of MyListbox.ScrollPositionY but it doesn't seem to exist.
Any ideas?
Chris
You need to get hold of the ScrollViewer that is used by the ListBox internally so you can grab the value of the VerticalOffset property and subsequently call the SetVerticalOffset method.
This requires that you reach down from the ListBox through the Visual tree that makes up its internals.
I use this handy extension class which you should add to your project (I've gotta put this up on a blog because I keep repeating it):-
public static class VisualTreeEnumeration
{
public static IEnumerable<DependencyObject> Descendents(this DependencyObject root, int depth)
{
int count = VisualTreeHelper.GetChildrenCount(root);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(root, i);
yield return child;
if (depth > 0)
{
foreach (var descendent in Descendents(child, --depth))
yield return descendent;
}
}
}
public static IEnumerable<DependencyObject> Descendents(this DependencyObject root)
{
return Descendents(root, Int32.MaxValue);
}
public static IEnumerable<DependencyObject> Ancestors(this DependencyObject root)
{
DependencyObject current = VisualTreeHelper.GetParent(root);
while (current != null)
{
yield return current;
current = VisualTreeHelper.GetParent(current);
}
}
}
With this available the ListBox (and all other UIElements for that matter) gets a couple of new extension methods Descendents and Ancestors. We can combine those with Linq to search for stuff. In this case you could use:-
ScrollViewer sv = SomeListBox.Descendents().OfType<ScrollViewer>().FirstOrDefault();

Resources