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

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.

Related

How to listen the number of touches?

I thought it's easy. Like always
//somewhere inside constructor
overlay.addOnTouchListener(this)
//...
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
event?:return false
if (event.actionMasked == MotionEvent.ACTION_DOWN || event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
//start drag
moving=true
} else if (event.actionMasked == MotionEvent.ACTION_MOVE) {
if (!moving) return true
//do drag
} else if (event.actionMasked == MotionEvent.ACTION_UP) {
//stop drag
println("touch:up(${event.pointerCount})")
}
return true
}
I was expecting MotionEvent.ACTION_UP will fire up on release of each finger.But looks like it only fires once for the last finger.
Is there way catch moment when user releases one finger but keep's moving another one?
You can use two methods getPointerCount(x) and/or getPointerId(x).
getPointerCount gets the number of pointers of data contained in an event. This is always >= 1.
While getPointerId() returns the pointer identifier associated with a particular pointer data index in an event. The identifier tells you the actual pointer number associated with the data, accounting for individual pointers going up and down since the start of the current gesture.
So in your case, if you want to capture the pointer that was not removed from the screen, you can use getPointerCount to check if there has been a pointer removed and then use getPointerId to assign some sort of function when the last pointer has been released.
The initial statement is incorrect. Actualy android notifies all touch ups with events MotionEvent.ACTION_UP/MotionEvent.ACTION_POINTER_UP

What happens when back button is pressed before asynchronous call is completed?

I have view models that are being stored in an array list on the application class. So their lifetime continues even if the activity gets destroyed because of rotation (however once isFinishing is true then the view model instance is removed from the list and ceases to exist).
I also have data service singletons that are used by the view models that also live indefinitely. So if I start an async call in my view model using the anko async block i.e.
async {
val data = DataService.instance.getData()
uiThread {
if (data != null) {
//do something
}
}
}
What happens if the user presses the back button before the call completes? IsFinishing will be true and my view model instance will no longer exist. Will the async call exception when it returns or will it die gracefully?
The code within uiThread call won't get executed if the underlying activity/fragment context has been garbage collected. A uiThread call within an async call will hold a WeakReference to the context, so the often encountered context memory leak won't occur. Details here.
I guess it will gracefully die. You could write a small test program in which you debug the behaviour. However, I would strongly suggest to keep a reference/pointer to the asynchronous task and kill it when you press the back button. No need to let it run in the background if you do not need the result / cannot handle the result anymore right

When to 'return' in an Objective-C method

Just a quick question. I was just wandering whether or not, I still have to "return;" even in a void function?
At the moment, even in methods which are not returning a variable/etc... I still have "return" at the end of the method.
So do I still need this? Because I swear without it, it does NOT return to where it was called from.
EG:
-(void)viewDidLoad {
[super viewDidLoad];
// Run other setup code....
// Run method 1.
[self method_01];
// Run next bit of code....
}
-(void)method_01 {
// Run code....
return;
}
Do I still have to do it like the above example?
Thanks for your time, Dan.
If the return is at the end of the method, it doesn't make any difference.
-(void) doSomethingWithX:(int) X
{
..........................
........some Code.........
..........................
return ;
}
The control would reach the caller one the method execution completes. Marking a return does the same.
However in a condition like below,
-(void) doSomethingWithX:(int) X
{
if(X>10)
{
return;
}
..........................
........some Code.........
..........................
}
The some code will not be executed if your X value is greater than 10. So, by default control return to the caller at the end of method. Use return if you want to force a return to caller in between the method execution.
You do not. The method will return to its previous point of execution once it reaches the end of the current scope.
You do not need to call return in methods that are defined with void and thus do not return a value.
There are times when you would want to call return in such methods, such as if you want to exit out of the method without executing the remaining code, if a particular condition is met:
if (iHaveDeterminedIAmFinished) {
return;
}
... // code that would otherwise execute.
Other than this, it would be bad practice to routinely include return at the end of every method. Every Objective-C method returns without exception, if it reaches the end of the method without a previous return. Therefore, this practice would not be more clear to a reader who has any familiarity with Objective-C. Indeed, it would likely confuse other developers reading your code who would be left wondering what the intention was. It would be likely to appear like something had been omitted from the end of the method, since there would be no reason for including this return otherwise. In short, I suggest it would be bad practice to include unnecessary return calls at the end of methods.
Because I swear without it, it does NOT return to where it was called from.
Something else is going on here. You may well need to figure out what it is, but it is not correct that the absence of return calls would prevent a return to the point of execution. Either it is returning, and you're not realising it for some reason, or something else is happening in your code.
You can do it either way. It should return automatically without an explicit return.

How do I fix yield not working in while loop?

I get no console errors, but all of them isntantiate at the same time, so they are all one unit, and I want a delay between their spawn. (they are enemies traveling a path)
#pragma strict
// Instantiate a rigidbody then set the velocity
var projectile : Transform;
var cnt : int = 0;
function Update () {
if (buttonFeatures.started) {
while (cnt < 4) {
// Instantiate the projectile at the position and rotation of this transform
wait();
var clone : Transform;
clone = Instantiate(projectile, transform.position, transform.rotation);
cnt++;
}
}
}
function wait(){
yield WaitForSeconds (10);
}
Your problem is you're trying to something similar to yield from Update(), which can't be done.
You can't obviously block Update() for 10 seconds, but calling a method that usesyield will return *immediately *and start a coroutine with that method, so what you're seeing is:
Update calls wait()
Update keeps going without waiting for wait() to return
wait() starts waiting for 10 seconds on it's own as a coroutine
Update continues through the loop, calling wait() 3 more times, not waiting each time.
To confirm this you can change wait():
function wait(){
yield WaitForSeconds (10);
Debug.Log("Done Waiting"); //You'll see 3 of these pop up in your console in 10 seconds later
}
You have two main options here. Either replace wait() with your logic:
function Update () {
if (buttonFeatures.started) {
while (cnt < 4) {
InstantiateProjectile(cnt*10)// Instantiate the projectile at the position and rotation of this transform in X seconds. This will return immediately
cnt++;
}
}
}
function InstantiateProjectile(delay : int){
yield WaitForSeconds(delay);
var clone : Transform;
clone = Instantiate(projectile, transform.position, transform.rotation);
}
Or start a co-routine in Start():
function Start(){
UpdateProjectiles();
}
function UpdateProjectiles (){
while(true){
if (buttonFeatures.started) {
while (cnt < 4) {
yield WaitForSeconds (10); //This works because it's not in Update
var clone : Transform;
clone = Instantiate(projectile, transform.position, transform.rotation); // Instantiate the projectile at the position and rotation of this transform
cnt++;
}
}
yield; //This causes this coroutine to behave the way Update would (running once a frame)
}
}
The while(true) in the second example might be a little alarming, but it's performance is no different than using Update() because of the yield. In fact, many people use the majority of their "traditional" Update() logic in co-routines, as they allow better encapsulation of state management logic, and are great for periodic tasks.
Note: I didn't want to distort your code too much and obscure it's meaning, but you might want to reconsider certain parts of your code:
You have a while loop with a count, that can easily be a for loop.
You have a loop that seems to be replacing objects. Instantiate can be one of the most expensive calls you can make, because for every call you make to it, eventually you'll pay the cost of the GC cleaning up an object.
You don't want to be destroying lots of objects and calling Instantiate to replace them with identical ones, because the GC will start slowing your game to a standstill keeping up. Right now as your code stands, if projectiles start being spawned in a situation where they're being destroyed very quickly, I won't be surprised if the game completely freezes.
Instead, prefer reusing objects, with object pools. There are tutorials on how to do it, such as this one. At the most basic level, it can be something as simple as giving your projectiles a Reset method. Then you could replace Destroy with a method that calls Reset and stores them in a Stack or List, where they can be accessed again. But you'll want to encapsulate all that logic, so look at that tutorial for specifics.
replace this line instead of making the function call:
yield return new WaitForSeconds(10);

is there way to check if performSelector:withObject:afterDelay: has been registered?

I whould like to know if there is a way to determine if performSelector:withObject:afterDelay: for the given object has been called (registered to be called). (I could use cancelPreviousPerformRequestsWithTarget:selector:object: and re-call performSelector:withObject:afterDelay:, ok but I'm interested to know if there is the alternative).
Thanks
The best thing to do would be to make sure that the selector being called can be called multiple times safely.
For example, use a flag in the target object to track if the method has already been invoked e.g.
-targetSelector: (id) param
{
if (!hasBeenRun) // hasBeenRun is a boolean intance variable
{
hasBeenRun = true;
// other stuff
}
}