Cocos2D-X Notify multiple objects of unique event has occured - event-handling

Looking for help on how to setup "EventListenerCustom" class instance so that I can broadcast to all objects a unique trigger has occurred. In older versions of Cocos2D-X, there was CCNotification, where I could set a flag and all my objects could check to see what the flag value was and based on whichever flag that an object reacted too would take an action.
I have tried looking for example where I could put all the movement, rotation, firing logic in one class and my other objects would take its specific action based on the flag that one class could control and change.

I would do this by creating a vector that keeps lambda functions.
class EventListenerCustom : public cocos2d::Layer
{
public:
virtual bool init();
CREATE_FUNC(EventListenerCustom);
void startFire();
void addFiringEventListener(std::function<void ()> listener);
protected:
std::vector<std::function<void()>> _firingEvents;
};
void EventListenerCustom::addFiringEventListener(std::function<void ()> listener)
{
_firingEvents.push_back(listener);
}
void EventListenerCustom::startFire()
{
for( const auto &child : _firingEvents)
child();
}
Or you can create a CustomEvent class for holding the lambda function and the target node in order to check if the target node is not null.

Related

Argument exception when I try to set a variable with a custom set in unity

I tried to use the Generate() function only if a variable has changed without having to check it every frame. I used the following tutorial to achieve this. but for some reason, whenever i try to set the variable, I get this error:
ArgumentException: GetComponent requires that the requested component 'List`1' derives from MonoBehaviour or Component or is an interface.
the script:
public GameObject CEMM;
private int ListLength;
public static int ListLengthProperty
{
get
{
return JLSV.instance.ListLength;
}
set
{
JLSV.instance.ListLength = value;
JLSV.instance.Generate();
}
}
private void Awake()
{
instance = this;
}
I tried to set the value like this: JLScrollView.ListLengthProperty = JLScrollView.instance.CEMM.GetComponent<List<JLClass>>().Count;
The generic type parameter that you use when calling GetComponent must be a class that derives from Component (or an interface type). List is a plain old class object, which is why you are getting the exception from this:
GetComponent<List<JLClass>>()
I'm not really sure what value you are trying to assign to the property. If you are trying to get the number of components of a certain type on the GameObject you can use GetComponents.
JLScrollView.ListLengthProperty = JLScrollView.instance.GetComponents<JLClass>().Length;

Define execution order for same script on multiple gameobjects

I have the same scrolling script attached to multiple game objects. But I want them executed in sequence. At present they were executing, I can say randomly so they aren't able to achieve synchronisation with each other in order.
So I want them executed based on each gameobject's order rather then each one randomly selected.
You can define your own UpdateManually method and call it in the appropriate order yourself. For example:
public class ScrollScriptUpdater : MonoBehaviour
{
// set references according to desired update order
// this can be done in the editor or via script if appropriate
public List<ScrollScript> ScrollScripts;
void Update ()
{
// this updates in the natural order of the list,
// list item 0, 1, 2, ...
foreach (var script in ScrollScripts)
{
script.UpdateManually();
}
}
}
public class ScrollScript : MonoBehaviour
{
public void UpdateManually()
{
// do stuff
}
}

Check if spawn is empty

I have two spawn spots where a player will show up upon connection.
I need that, when one of the players connects on one of the spots, any other player will always spawn at the other spot.
Here's some visual in case it helps: https://goo.gl/Y0ohZC
Here is the code I'm using:
using UnityEngine;
using System.Collections;
public class SpawnSpot : MonoBehaviour {
public int teamId=0;
public GameObject[] Spots; //Drag the spots in here (In the editor)
bool[] OccupiedSpawnSpots;
//Using Photon Networking
void OnJoinedRoom()
{
//Request the recent OccupiedSpawnSpots List
PhotonView.RPC("RequestList", PhotonTargets.MasterClient, PhotonNetwork.player);
}
//In "RequestList" the MasterClient sends his List of the SpawnSpots
//by calling "ReceiveList"
[RPC]
void RequestList(PhotonPlayer player)
{
PhotonView.RPC("ReceiveList", PhotonTargets.All, player, OccupiedSpawnSpots);
}
[RPC]
void ReceiveList(PhotonPlayer Sender, bool[] ListOfMasterClient)
{
OccupiedSpawnSpots = ListOfMasterClient;
//Get the free one
if (OccupiedSpawnSpots[0] == false)
{
//Spawn player at 0
if (Sender == PhotonNetwork.player)
PhotonNetwork.Instantiate("PlayerController", Spots[0].transform.position);
OccupiedSpawnSpots[0] = true;
}
else
{
//Spawn player at 1
if (Sender == PhotonNetwork.player)
PhotonNetwork.Instantiate("PlayerController", Spots[1].transform.position);
OccupiedSpawnSpots[1] = true;
}
}
The errors given are:
Assets/Scripts/SpawnSpot.cs(14,28): error CS0120: An object reference
is required to access non-static member `PhotonView.RPC(string,
PhotonPlayer, params object[])'
Assets/Scripts/SpawnSpot.cs(22,28): error CS0120: An object reference
is required to access non-static member `PhotonView.RPC(string,
PhotonPlayer, params object[])'
Assets/Scripts/SpawnSpot.cs(36,47): error CS1501: No overload for
method Instantiate' takes3' arguments
Assets/Scripts/SpawnSpot.cs(43,47): error CS1501: No overload for
method Instantiate' takes3' arguments
Thanks in advance, IC
It appears that you are trying to call an instance function using a static reference. instead of doing PhotonView.RPC("RequestList", PhotonTargets.MasterClient, PhotonNetwork.player);
you need to create a reference to an PhatorView object, and then call the RPC function on it.
public PhotonView photonView;
void OnJoinedRoom()
{
if(photonView == null)
{
photonView = GetComponent<PhotonView>();
}
//Request the recent OccupiedSpawnSpots List
PhotonView.RPC("RequestList", PhotonTargets.MasterClient, PhotonNetwork.player);
}
you should have a PhotonView object on the same GameObject that this script is on, or assign a reference to a PhotonView in the editor.
That should fix your problems, but I think you should look into compiler errors and how to to fix them. In Unity3D if you double click the error in the console it will take you to the line that isn't compiling. It also tends to give you a pretty good hint as to why it isn't compiling.
your error was this
"Assets/Scripts/SpawnSpot.cs(14,28): error CS0120: An object reference is required to access non-static member `PhotonView.RPC(string, PhotonPlayer, params object[])'"
which means that you need an object in order to call this function.
The third and fourth errors are because you are calling Instantiate with only 2 arguments, but it takes at least 4. Include the rotation of the GameObject you're trying to instantiate, and a group number:
PhotonNetwork.Instantiate("PlayerController", Spots[0].transform.position, Quaternion.identity, 0);
Note that you may not want the identity quaternion, so you may need to change this. Also I'm not familiar with PhotonNetwork so 0 may not be an advisable group.

Why does getting the nth child of a Node fail in an ExplorerManager listener?

I'm having problems with the NetBeans Nodes API.
I have this line of code:
Node n = (new MyNode(X)).getChildren().getNodeAt(Y);
The call to new MyNode(X) with the same X always initializes a MyNode the same way, independent of the context.
When I place it by itself (say, in an menu action), it successfully gets the Yth child, but if I put it in an event where other Node/Children stuff happens, it returns null.
MyNode's Children implementation is a trivial subclass of Children.Keys, which is approximately:
// Node
import org.openide.nodes.AbstractNode;
class MyNode extends AbstractNode {
MyNode(MyKey key) {
super(new MyNodeChildren(key));
}
}
// Children
import java.util.Collections;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
public class MyNodeChildren extends Children.Keys<MyKey> {
MyKey parentKey;
MyNodeChildren(MyKey parentKey) {
super(true); // use lazy behavior
this.parentKey = parentKey;
}
#Override
protected Node[] createNodes(MyKey key) {
return new Node[] {new MyNode(key)};
}
#Override
protected void addNotify() {
setKeys(this.parentKey.getChildrenKeys());
}
#Override
protected void removeNotify() {
setKeys(Collections.EMPTY_SET);
}
}
// MyKey is trivial.
I assume this has something to do with the lazy behavior of Children.Keys. I have the sources for the API, and I've tried stepping through it, but they're so confusing that I haven't figured anything out yet.
NetBeans IDE 7.0.1 (Build 201107282000) with up-to-date plugins.
Edit: More details
The line with the weird behavior is inside a handler for an ExplorerManager selected-nodes property change. The weird thing is that it still doesn't work when the MyNode instance isn't in the heirarchy that the ExplorerManager is using (it's not even the same class as the nodes in the ExplorerManager), and isn't being used for anything else.
Accessing the nodes instead of the underlying model is actually necessary for my use case (I need to do stuff with the PropertySets), the MyNode example is just a simpler case that still has the problem.
It is recommended to use org.openide.nodes.ChildFactory to create child nodes unless you have a specific need to use one of the Children APIs. But for the common cases the ChildFactory is sufficient.
One thing to keep in mind when using the Nodes API is that it is only a presentation layer that wraps your model and used in conjunction with the Explorer API makes it available to the various view components in the NetBeans platform such as org.openide.explorer.view.BeanTreeView.
Using a model called MyModel which may look something like:
public class MyModel {
private String title;
private List<MyChild> children;
public MyModel(List<MyChild> children) {
this.children = children;
}
public String getTitle() {
return title;
}
public List<MyChild> getChildren() {
return Collections.unmodifiableList(children);
}
}
You can create a ChildFactory<MyModel> that will be responsible for creating your nodes:
public class MyChildFactory extends ChildFactory<MyModel> {
private List<MyModel> myModels;
public MyChildFactory(List<MyModel> myModels) {
this.myModels = myModels;
}
protected boolean createKeys(List<MyModel> toPopulate) {
return toPopulate.addAll(myModels);
}
protected Node createNodeForKey(MyModel myModel) {
return new MyNode(myModel);
}
protected void removeNotify() {
this.myModels= null;
}
}
Then, implementing MyNode which is the presentation layer and wraps MyModel:
public class MyNode extends AbstractNode {
public MyNode(MyModel myModel) {
this(myModel, new InstanceContent());
}
private MyNode(MyModel myModel, InstanceContent content) {
super(Children.create(
new MyChildrenChildFactory(myModel.getChildren()), true),
new AbstractLookup(content)); // add a Lookup
// add myModel to the lookup so you can retrieve it latter
content.add(myModel);
// set the name used in the presentation
setName(myModel.getTitle());
// set the icon used in the presentation
setIconBaseWithExtension("com/my/resouces/icon.png");
}
}
And now the MyChildrenChildFactory which is very similar to MyChildFactory except that it takes a List<MyChild> and in turn creates MyChildNode:
public class MyChildFactory extends ChildFactory<MyChild> {
private List<MyChild> myChildren;
public MyChildFactory(List<MyChild> myChildren) {
this.myChildren = myChildren;
}
protected boolean createKeys(List<MyChild> toPopulate) {
return toPopulate.addAll(myChildren);
}
protected Node createNodeForKey(MyChild myChild) {
return new MyChildNode(myChild);
}
protected void removeNotify() {
this.myChildren = null;
}
}
Then an implementation of MyChildNode which is very similar to MyNode:
public class MyChildNode extends AbstractNode {
public MyChildNode(MyChild myChild) {
// no children and another way to add a Lookup
super(Children.LEAF, Lookups.singleton(myChild));
// set the name used in the presentation
setName(myChild.getTitle());
// set the icon used in the presentation
setIconBaseWithExtension("com/my/resouces/child_icon.png");
}
}
And we will need the children's model, MyChild which is very similar to MyModel:
public class MyChild {
private String title;
public String getTitle() {
return title;
}
}
Finally to put it all to use, for instance with a BeanTreeView which would reside in a TopComponent that implements org.openide.explorer.ExplorerManager.Provider:
// somewhere in your TopComponent's initialization code:
List<MyModel> myModels = ...
// defined as a property in you TC
explorerManager = new ExplorerManager();
// this is the important bit and we're using true
// to tell it to create the children asynchronously
Children children = Children.create(new MyChildFactory(myModels), true);
explorerManager.setRootContext(new AbstractNode(children));
Notice that you don't need to touch the BeanTreeView and in fact it can be any view component that is included in the platform. This is the recommended way to create nodes and as I've stated, the use of nodes is as a presentation layer to be used in the various components that are included in the platform.
If you then need to get a child you can use the ExplorerManager which you can retrieve from the TopComponent using the method ExplorerManager.Provier.getExplorerManager() which was implemented due to the fact that your TopComponent implemented ExplorerManager.Provider and is in fact the way that a view component itself gets the nodes:
ExplorerManager explorerManager = ...
// the AbstractNode from above
Node rootContext = explorerManager.getRootContext();
// the MyNode(s) from above
Children children = rootContext.getChildren().getNodes(true);
// looking up the MyModel that we added to the lookup in the MyNode
MyModel myModel = nodes[0].getLookup().lookup(MyModel.class);
However, you must be aware that using the Children.getNodes(true) method to get your nodes will cause all of your nodes and their children to be created; which weren't created due to the fact that we told the factory that we wanted it to create the children asynchronously. This is not the recommended way to access the data but instead you should keep a reference to the List<MyModel> and use that if at all possible. From the documentation for Children.getNodes(boolean):
...in general if you are trying to get useful data by calling this method, you are probably doing something wrong. Usually you should be asking some underlying model for information, not the nodes for children.
Again, you must remember that the Nodes API is a presentation layer and is used as an adapter between your model and your views.
Where this becomes a powerful technique is when using the same ChildFactory in different and diverse views. You can reuse the above code in many TopComponents without any modifications. You can also use a FilterNode if you need to change only a part of the presentation of a node without having to touch the original node.
Learning the Nodes API is one of the more challenging aspects of learning the NetBeans platform API as you have undoubtedly discovered. Once you have some mastery of this API you will be able to take advantage of much more of the platforms built in capabilities.
Please see the following resources for more information on the Nodes API:
NetBeans Nodes API Tutorial
Great introduction to the Nodes API by Antonio Vieiro
Part 5: Nodes API and Explorer & Property Sheet API by Geertjan Wielenga
JavaDocs for the Nodes API
Timon Veenstra on the NetBeans Platform Developers mailing list solved this for me.
Actions on the explorerManager are guarded to ensure consistency. A
node selection listener on an explorer manager for example cannot
manipulate the same explorer manager while handling the selection
changed event because that would require a read to write upgrade. The
change will be vetoed and die a silent death.
Are you adding the MyNode root node to the explorer manager on
initialization, or somewhere else in a listener?
My problem line is in an ExplorerManager selection change listener. I guess the Children.MUTEX lock is getting set by ExplorerManager and preventing the Children.Keys instance from populating its Nodes...?
Anyways, I moved my Node access into a EventQueue.invokeLater(...), so it executes after the selection changed event finishes, and that fixed it.

Is there a disposing TransientLifetimeManager

I have a WPF view that has a corresponding ViewModel. All instances are resolved via an unity container. Because I'm using prism I need two independent instances of the view to add it into two different regions the view is registered to. If I'd try to add one instance into both regions I get an
InvalidOperationException: Specified
element is already the logical child
of another element. Disconnect it
first.
when the view is added into the second region because it is already added to the first region.
This problem can easily be solved by using a TransientLifetimeManager that always returns a new instance so both regions would be filled with an independent instance.
But we have decided to create a child container when a new user logs on. Every session related view and view model are resolved using this child container. When the user's session ends, the child container is disposed so that also every session related instances are disposed. But using a TransientLifetimeManager the unity container cannot dispose those instances.
What we need is a lifetime manager that always returns a new instance, but is also capable of disposing those instances. Is there already such an lifetime manager around? Or is there another way to achieve what I described above?
What you want sounds like a variant of the ContainerControlledLifetime manager that does not maintain a singleton instance, but a collection of instances. Unfortunately this is not one of the built-in lifetime managers.
You can look at the code for the ContainerControlledLifetimeManager and see that it is pretty simple. Your "SynchronizedGetValue" implementation would always return null (signaling to the container that a new instance needs to be instantiated). You could just subclass ContainerControlledLifetimeManager and override that method.
I've pretty much written it. I suppose I could give you the code. :)
public class ContainerTrackedTransientLifetimeManager :
ContainerControlledLifetimeManager
{
protected override object SynchronizedGetValue()
{
return null;
}
}
That should work. I've not tested it... from the interface, it looks like it's designed for a 1 to 1 LifetimeManager to Object relationship, but if it turns out it is more than that, you might have to override SetValue (adds to a collection of objects) and dispose (disposes that collection of objects). Here's that implementation:
public class ContainerTrackedTransientLifetimeManager :
SynchronizedLifetimeManager, IDisposable
{
private ConcurrentCollection<object> values = new ConcurrentCollection<object>();
protected override object SynchronizedGetValue()
{
return null;
}
protected override void SynchronizedSetValue(object newValue)
{
values.Add(newValue);
}
public override void RemoveValue()
{
Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
var disposables = values.OfType<IDisposable>();
foreach(var disposable in disposables)
{
disposable.Dispose();
}
values.Clear();
}
I'm not sure which of these is the right answer. Let me know how it goes for you.
When you use transient lifetime manager (which is the default), Unity does not keep a reference to the created instance.
Thus, when there are no more reference to the instance, it will be GCed.