Does performing a SCNAction on a SCNNode change the nodes position? - scenekit

I was wondering if anyone knew if you perform a SCNAction on a node, is there a way while that node is executing the action, where you could find out what position it's in the scenes coordinate system?
Lets say I have two SCNNodes A and B...
SCNNode *A, *B;
and I want to run a SCNAction for A
A.position = SCNVector3Make(0.0,0.0,0.0);
[A runAction:[SCNAction moveTo:SCNVector3Make(10.0,0.0,0.0)]];
and while A was running its action, have B follow it in real time?
[B runAction:[SCNAction repeatActionForever:[SCNAction moveTo:A.position]]];
So every time B repeats its given a new updated position of A to move to.
The problem I'm getting is, even if I set the presentationNode of A to the SCNAction above, It's still returning the initial input that I set (which makes sense) but how do I get the updated position of A?
Side Note: When I take A.presentationNode.position I get the default Zero Vector
SOLVED QUESTION
After further research, I found out how to use the SCNSceneRendererDelegate and then created a (void) method which updated the position of node A and then within the same method I had a SCNAction which moved B to the update position of A.
If anyone had a similar issue or would just like to see the code, let me know and I'll post it!

A.position is evaluated once and only once, when you create the action:
[SCNAction moveTo:A.position]
There is no block involved here that gives you a chance to customize the action as time passes.

I know this is an old question, but you could have used a SCNDistanceConstraint with a distance of zero.
You could also simply have created a property on B that you assign A to. Then, for B, use a custom action to access that. e.g.
class BNode : SCNNode
var ANodeInstance : SCNNode? = nil
init(withANode: SCNNode) {
super.init()
self.ANodeInstance = withANode
}
}
B.runAction(SCNAction.repeatActionForever(
SCNAction.customAction(duration: duration, action: { (node, timeElapsed) in
let selfAsBNode = node as! BNode
selfAsBNode.position = selfAsBNode.ANodeInstance.position
})
Sorry, it's in Swift not Objective-C but it's pretty easy to translate back.
This sort of thing is ugly as blazes, but Apple haven't really provided any clean way to communicate state through a chain of actions.

Related

ngAnimate to detect changes from $http-call with interval

I have an array with a few items in it. Every x seconds, I receive a new array with the latest data. I check if the data has changed, and if it has, I replace the old one with the new one:
if (currentList != responseFromHttpCall) {
currentList = responseFromHttpCall;
}
This messes up the classes provided by ng-animate, as it acts like I replaced all of the items -- well, I do actually, but I don't know how to not.
These changes can occur in the list:
There's one (or more) new item(s) in the list - not necessaryly at the end of the list though.
One (or more) items in the list might be gone (deleted).
One (or more) items might be changed.
Two (or more) items might have been swapped.
Can anyone help me in getting ng-animate to understand what classes to show? I made a small "illustation" of my problem, found here: http://plnkr.co/edit/TS401ra58dgJS18ydsG1?p=preview
Thanks a lot!
To achieve what you want, you will need to modify existing list on controller (vm.list) on every action. I have one solution that may work for your particular example.
you would need to compare 2 lists (loop through first) similar to:
vm.list.forEach((val, index)=>{
// some code to check against array that's coming from ajax call
});
in case of adding you would need to loop against other list (in your case newList):
newList.forEach((val, index)=>{
// some code to check array on controller
});
I'm not saying this is the best solution but it works and will work in your case. Keep in mind - to properly test you will need to click reset after each action since you are looking at same global original list which will persist same data throughout the app cycle since we don't change it - if you want to change it just add before end of each function:
original = angular.copy(vm.list);
You could also make this more generic and put everything on one function, but for example, here's plnkr:
http://plnkr.co/edit/sr5CHji6DbiiknlgFdNm?p=preview
Hope it helps.

What's a more efficient way to do collisions?

Here's my dilemma
I have 4 walls around the stage of my game, when a player hits these walls I do not want to make an if statement for each and every one of the walls checking if the player is hitting it, so I have created an array to hold the walls, then check if the player is hitting that. Now, because I am doing this I will not know what the player is actually hitting if he hits something, and I cannot do a check in my array if he's hitting like [0], [1], [2] etc because then I'm back to doing the checks if he's hitting specific walls. The reason I don't want to do that is for the future, when I add more barriers, buildings, and so on.
So my question is, how can I do collision checks, without hard coding checks on specific objects, and giving some sort of value that can be used for the player to respond to, for example if your hitting the top wall and you can figure that out somehow without doing the above, then make it so you can't walk through or something,
if (main.playerPosKeeper_mc.hitTestObject(this[main.StageCollisions]))
{
trace("hit");
}
StageCollisions is an array which contains all of my barriers in it.
When the player hits anything in StageCollisions, I cannot just simply subtract from his y value, or x value, because I do not know which object he hit, but I also do not want to hard code it so that I check if I'm hitting lets say the top barrier, because then why do an array in the first place if I'm just going back to making static if else statements.
^^ Refrencing this topic
AS3 - How to Cycle States of Character Animations (moving & stopped)
This has been stumping me for a little while, so help would be greatly appreciated. It is a hard question to form so I can clarify points if necessary.
So my question is, how can I do collision checks, without hard coding
checks on specific objects, and giving some sort of value that can be
used for the player to respond to, for example if your hitting the top
wall and you can figure that out somehow without doing the above, then
make it so you can't walk through or something
Right, so you want a way to perform a generic collision response. This can be a big topic. The simplest approach is usually to check for a collision after a move, then reverse the move if there's a collision.
Something like this:
function movePlayer(movementX:Number, movementY:Number):void {
var originalX:Number = player.x;
var originalY:Number = player.y;
player.x += movementX;
if (checkCollision()) {
player.x = originalX;
}
player.y += movementY;
if (checkCollision()) {
player.y = originalY;
}
}
function checkCollision():Boolean {
for each (var wall:MovieClip in walls) {
if (player.hitTestObject(wall)) {
return true;
}
}
return false;
}
This way you could have checkCollision() check 4 walls or 50 walls, it doesn't matter. It won't let the player move into them.
This is just a starting point and there are many ways it can break down or be refined.
Some trivial pseudo code for you to study:
private function collisionCheck(h:Sprite):Sprite{ // pass the hero Sprite into this function and it will return the wall that it hit
for each (b:Sprite in blockArray){ // if your array of hit-able objects is called "blockArray"
if (h.hitTtestObject(b)){ // check the hero Sprite against all objects in the array
return b;
}
}
return null;
}
Then, elsewhere in your code (maybe in your gameTick function or gameLoop function or wherever you have your game logic repeating on each frame:
private function gameTick():void{
var objectHit:Sprite = collisionCheck(_myHero); // this will run the collision check function, and return the sprite that the hero collides with;
if (objectHit != null){
objectHit.alpha = 0.5;
// this will give you a visible representation that your code is indeed working, or not.
}
}
For those moments when your hero isn't colliding with anything, this function will return null. That's why I first check if objectHit is not null before trying to perform an operation on its alpha value. Of course, you will do something other than change its alpha value in your project, but this is something I often do (with the alpha) to quickly get a visual confirmation that things are detecting what they are supposed to.

Programmatically composing a chain

I would like to be able to programmatically compose a chain, for later inclusion in another chain. I know it can't be that hard, but I seem to be missing something.
In theory, I should be able to do something like this:
var c = ??? // the part I can't figure out
List( 1, 2, 3 ).foreach {
c.exec( http("Fetch something").get("..." + _ ) )
}
That is, I expect to be able to create a chain, then populate that chain in a loop, rather than hard-coding the chain in the source code.
My biggest struggle, I think, is knowing what to assign to c. I had assumed that it should be
var c = new ChainBuilder()
but according to the documentation I have to pass it a list of actionBuilders and the next action, implying that it is not possible to build an empty chain and then build on it in a separate statement.
Is there any way to make my .foreach loop work the way I intend it to work?
The answer is
import bootstrap._
and then
var c = bootstrap
But then the loop must be modified, like so:
List( 1, 2, 3 ).foreach( x => {
c = c.exec( ... )
})
The reason has to do with the fact that you have to do what chaining does. When you have
foo()
.bar()
.blip()
The result of the whole expression is the return value from blip and not foo - which is obvious when you think about it - so the variable that we are attaching to has to move as nodes are attached.
I hope someone, somewhere, besides me, finds value in seeing this example.

Movie Clip through Display Object Not working correctly

Hey everyone so I have a movie Clip called popEffect that i want to show on the current bubbles that are being clicked by the mouse. Now Whenever I click on a Bubble everything works correctly they get removed from the stage, but the problem I am having is that the popEffect is not positioned to the current bubbles that are being clicked. Instead they are positioned at a different bubble that shows on the screen in the display object array.
Here is how I have it all set up:
private function addBubbles(e:TimerEvent):void
{
bubbles = new mcBubbles();
stage.addChild(bubbles);
aBubbleArray.push(bubbles);
bubbles.addEventListener(MouseEvent.CLICK, bubblesBeingClicked);
}
Then the BubblesBeingClicked function:
private function bubblesBeingClicked(e:MouseEvent):void
{
var BubblePop:DisplayObject = e.target as DisplayObject; // HERE is your clicked square
var i:int = aBubbleArray.indexOf(BubblePop); // and HERE is your index in the array
if (i < 0)
{
// the MC is out of the array
//trace("Pop Clicked");
onBubbleIsClicked(BubblePop);
aBubbleArray.splice(i, 1);
BubblePop.parent.removeChild(BubblePop);
//Remove Listeners!!!
BubblePop.removeEventListener(MouseEvent.MOUSE_DOWN, onBubbleIsClicked);
// Null
BubblePop = null;
}
}
Finally my onBubbleIsClicked function where i have the popEffect located:
private function onBubbleIsClicked(bubblePop:DisplayObject):void
{
nScore++;
updateHighScore();
//Pop Effect
popEffect = new mcBubblePop();
stage.addChild(popEffect);
popEffect.x = bubbles.x;
popEffect.y = bubbles.y;
}
Can anyone see why the popEffect wont position on the current bubble that is being popped? Its acting really weird.
The reason is this:
popEffect.x = bubbles.x;
popEffect.y = bubbles.y;
As far as I can understand, bubbles is a member variable in the class (you are using it in the addBubbles function. Inside onBubbleIsClicked, you provide bubblePop, but do not use it. You are using bubbles instead, which is actually the last instance you've created inside the tick function!
So every time you create popEffect, you actually assign the x and y to the latest created bubblePop.
Some advises:
Do not use member variables that often. They are used WHEN you need to use a variable between functions. In your case, bubbles is a variable that is used only inside the creational function. You even put them into an array! And because you override it with a new one every time you create an instance, your member variables just saves the last one. Is this really needed? Same with popEffect, does anyone else uses it, as it's again just the last one? Such things create mistakes, as you see..
I truly don't understand what this means: if (i < 0). You search if the object you've clicked is not in the array? Well if it is not (how come?!), then what's the meaning of aBubbleArray.splice(i, 1);? Since i < 0, you actually splice with negative value, so you splice some other element! Plan what you want to do, thing logically and then do the actual code. If the object is not in the array, then why do you remove anything from the array?
Start formatting your code better. Read about camel case and variables scope.
Try to manage your logic better. For example this is pretty awkward: BubblePop.parent.removeChild(BubblePop);, as long as you've added it by using stage.addChild(bubbles);. So isn't it more simple to use stage.removeChild(child);? There are some rules in programming (especially in Flash), like 'what added it should remove it'. This will keep you safe in future.
Good luck!

How to effectively garbage collect in AS3

I have a flash game that I'm building where I have an array keeping track of a bunch of power ups on the screen. When the player goes an grabs one it needs to disappear from the screen (which is easy) but it also needs to be removed from the array so that collision detection loops don't become really cumbersome. I tried using splice, but I keep get null reference errors, here's the relevant code.
public function collect():void {
try {
Main.powerUps.splice(index, 1);
stage.removeChild(this);
}catch (e:Error) {
trace("Error in splice");
}
}
}
Then when I create my PowerUp object I pass it a parameter that gets assigned to index which is the length of the array of Power Ups at the time. Can anyone see what's wrong with this code or (preferably) provide a more elegant solution? Thanks in advance for any help.
Elegant solution: use indexOf() and splice() together!
var index:int = Main.powerUps.indexOf( powerup );
Main.powerUps.splice(index, 1);
Where powerup is a reference to the object stored within the array Main.powerUps.
I also created a little class a while back that may be useful to you:
https://github.com/MartyWallace/Lotus/blob/master/Lotus/lotus/utils/Set.as
It has a .remove() method so you can just do:
powerUps.remove(powerup);

Resources