Making a `FlxSubState` that can be re-used without it crashing on the second `open`? - haxeflixel

Typically, when I want to open a FlxSubState that I have defined in my code, I will use:
openSubState(new MySubState());
I have all of my create/add logic inside MySubState.create()
Which works fine, except, if there is a lot of stuff on that SubState it can cause a huge lag spike making the game 'freeze' before the substate is displayed.
If I try set a variable to my substate and re-use it, it works once, but then crashes the game when I try to open it a second time, because the substate is being auto-destoyed on close.

By default, when a FlxSubState closes, it is destroy()ed as well - removing all added objects, etc.
Also, since new and create are only called the very first time the substate is opened, anything you add there doesn't get re-added (and you don't want to have new/create called every time you open the substate, since that would not stop the lag-spike)
The solution is simple: in the FlxState that is opening your substate, there is a flag destroySubStates set this to false and the substates will not be destroyed on close.
...and how do you make changes to the substate between opens? You can use the openCallback in FlxSubState which gets triggered when you open the substate, after create gets called (if it does) and before the substate is displayed.
So:
If you want to have an updating FlxSubState that can be re-used to cut down on 'lag' when it is opened, here's what I did:
in my PlayState:
override public function create():Void
{
...
mySubState = new MySubState();
destroySubStates = false;
...
}
public function openMySubState():Void
{
openSubState(mySubState);
}
in MySubState:
public function new():Void
{
super(0);
openCallback = refresh;
}
override public function create():Void
{
// create and add all of my elements
}
private function refresh():Void
{
// anything that changed between last time it was open and now, update .text/etc
}
AND this cuts out the lag spike everytime you open the substate!
...just remember to call mySubState.destroy(); inside your PlayState.destroy(); to clean up properly!

Related

Is this the correct way to stop a function and restart it with new data?

I have a function which does a bunch of searching and setting fields. Now, I want it to stop doing that and restart as soon as I change anything, is this the correct way of doing that?
The plan is that I don't have work being done that is no longer used, and that slower updates don't finish after a more recent, faster update
private var autoUpdateJob: Job = Job()
(...)
// Something happens (eg. an onTextChangedListener in an EditText gets triggered)
launch {
autoUpdateJob.cancelAndJoin()
autoUpdateJob = launch { flight = autoValues() }
}

How can I force shell to push an object after self destroying with delay (Unity3D)

I have an object inside a boundary and I shoot into the object (to understand my code see this lesson: https://unity3d.com/learn/tutorials/projects/space-shooter/creating-hazards?playlist=17147). Shell (bullet) should be destroyed after collision with object, but not instantly - after some delay (i.e. they collides and after some amount of seconds shell disappears). Shell's collider should be with a trigger, but because of it she flies through the object. Shell should disappear after it affected the object. I made the delay in order to have time for affecting. But if there a way it can disappear instantly then that's great. I just wanted give time to shell to apply a force.
void OnTriggerEnter(Collider other) {
if (other.tag == "Boundary")
{
return;
}
//Destroy (gameObject);
StartCoroutine(WaitAndDestroy());
}
IEnumerator WaitAndDestroy() {
yield return new WaitForSeconds(2);
Destroy (gameObject);
}
Try to move StartCoroutine(WaitAndDestroy()); above the return statement.
It is nesessary to use OnCollisionEnter(Collision other), and put Destroy(other.gameObject) into it. And colliders should be without triggers - on both interacting objects.

MyBase initialize() in Membership Provider

In my code I use this line to Initialize my Base:
MyBase.Initialize(name, config)
Everything goes fine in the first time pass... but when it passes second time then throws me an error The Base Is already Initialized and that is something I don't want to happen.
Is there any way to catch this event?
Finally the Base initialized only in the Default.aspx page, putting these lines in the Page_Load:
Dim myNewAsp As New AspNetSqlProvider
If MyAspNetSqlMembershipProvider.SQLconnectionString = Nothing Then
myNewAsp.InitializeSite(sender, e)
Return
End If
Doing this the system always knows when if the Base is initialized or not.

how to deal with Element is already the child of another element? [duplicate]

At first, this exception doesn't really make sense to me. Why shouldn't i be able to duplicate this object multiple times? but thats not the point:
i use a List. Whenever i navigate to a site, it should do this:
(App.Current as App).recent.ForEach(x => container.Children.Add(x));
(container = another StackPanel)
the first time, it works. afterwards, i get the exception displayed in the questiontitle. i already tried using a listbox, but i just got a ArgumentException. I think these exceptions have the same source, but i don't know what i'm doing wrong. please help
thanks
The error is quite clear: A WPF/SL Control can only belong to 1 Parent control at a time.
So you'll either have to remove the Controls from their Parent when you are moving away from a Page or you'll have to Create (possibly Clone) new Controls in this ForEach.
When you navigate to a page, the old instance is not removed instantly, so when you add your controls to the new page, they may still be used in the old page if it's not destroyed, causing the exception.
Try overriding the OnNavigatedFrom(NavigationEventArgs e) and OnNavigatingFrom(NavigatingCancelEventArgs e) methods that are invoked when you leave a page so that you empty your StackPanel.
For example, you could do :
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
container.Children.Clear();
}
You have to remove the container's children when you navigate from the page. But not if the navigation is due to a suspend. To avoid the children clear when the navigation is due to a suspend it is better to override OnNavigatingFrom instead of OnNavigatedFrom
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
container.Children.Clear();
base.OnNavigatingFrom(e);
}

Dojo: Is there an event after drag & drop finished

I've got two dojo.dnd.Sources with items. Whenever an item is dropped I need to persist the new order of the items in the Sources using an xhr.
Is there an dojo event or topic that is fired after an dnd operation has (successfully) finished? What would be the best way to use it?
Probably I don't understand the problem in all details but I don't see why you need to process events or topics. The best way to record changes is to intercept updating methods on relevant sources. Specifically you need to intercept insertNodes() for drops or any other additions.
Simple example (pseudo-code):
var source1, source2;
// ...
// initialize sources
// populate sources
// ...
function getAllItems(source){
var items = source.getAllNodes().map(function(node){
return source.getItem(node.id);
});
return items;
}
function dumpSource(source){
var items = getAllItems(source);
// XHR items here to your server
}
function recordChange(){
// now we know that some change has occured
// it could be a drop or some programmatic updates
// we don't really care
dumpSource(source1);
dumpSource(source2);
}
dojo.connect(source1, "insertNodes", recordChanges);
dojo.connect(source2, "insertNodes", recordChanges);
// now any drop or other change will trigger recordChanges()
// after the change has occurred.
You can try to be smart about that and send some diff information instead of a whole list, but it is up to you to generate it — you have everything you need for that.
You can use dojo.subscribe to do something when a drop is finished like so:
dojo.subscribe("/dnd/drop", function(source, nodes, copy, target) {
// do your magic here
});
There's examples of using subscribe on the dojotoolkit tests site. More info about dojo publish and subscribe too.
Alternately, you could connect to the onDndDrop method.
var source = new dojo.dnd.Source( ... );
dojo.connect( source, "onDndDrop", function( source, nodes, copy, target ) {
// make magic happen here
});
connect methods are called at the end so the items will be there at that point.
I'm keeping this note for dojo Tree folks just like me who would run in to this problem. Solutions given here was not quite worked well in my situation. I was using a dijit.tree.dndSource with Dojo tree and subscribing to "/dnd/drop" allows me to capture the event even though at that point my underlying data store hadn't been updated with latest changes. So I tried waiting as Wienczny explains, that doesn't solve the problem completely as I can't rely on a timeout to do the waiting job. Time taken for store update could be vary, i.e. shorter or very long depends on how complex your data structure is. I found the solution with overriding the onDndDrop method of the dndController. Simply you can specify the onDndDrop : on your tree initialization. One thing I found odd though you can not hitch this method, you will get weird behavior during dnd.
Tree
this._tree = new MapConfigTree({
checkAcceptance: this.dndAccept,
onDndDrop: this.onDndDrop,
betweenThreshold:5,
method
onDndDrop : function(source, nodes, copy, target){
if(source.dropPosition === 'Over' && (target.targetAnchor.item.type[0] == 'Test layer')) {
this.inherited(arguments);
// do your bit here
} else {
this.onDndCancel();
}
}