cocos2d-x: Rotating CCSprite while moving changes it's final position - cocos2d-x

I'm trying to make an animation for my game, of an ant leaving it's nest. It should descend the nest going right and down, facing down and then look straight again.
I created two sequences of actions, one for moving and the other for rotating and put them together in a CCSpawn. If I execute only the moving action it works fine, but when the actions are executed together, at the end the sprite moves back to it's original position.
I have no idea of what's happening. Can you guys help?
CCLayer * gameLayer = CCLayer::create();
Ant* ant = Ant::create(); // Ant is a CCSprite
CCPoint nestp = ccp(45, 172);
ant->setPosition(nestp);
gameLayer->addChild(ant);
addChild(gameLayer);
// ant walking animation
CCAnimate * antWalk = CCAnimate::create(_antWalk);
ant->runAction(CCRepeatForever::create(antWalk));
CCPoint p1 = ccp(55, 165), p2 = ccp(75,160), p3 = ccp(90,110), p4 = ccp(105, 50);
CCSequence *moveOut = (CCSequence *)CCSequence::create(CCMoveTo::create(0.3, p1), CCMoveTo::create(0.3, p2), CCMoveTo::create(0.7, p3), CCMoveTo::create(0.7, p4), NULL);
CCSequence *rotateOut = (CCSequence *) CCSequence::create(CCRotateTo::create(0.5, 50), CCDelayTime::create(1), CCRotateTo::create(0.5, 0));
CCSpawn *leaveNest = (CCSpawn *)CCSpawn::create(moveOut, rotateOut, NULL);
ant->runAction(leaveNest);

When reviewing my own question I realized that I had forgotten to add NULL to the end of the rotating sequence. It should be like this:
CCSequence *rotateOut = (CCSequence *) CCSequence::create(CCRotateTo::create(0.5, 50), CCDelayTime::create(1), CCRotateTo::create(0.5, 0), NULL);
I wouldn't expect this behaviour, as there were no errors, that's why I took so long to find out but now it works fine! I hope it'll help someone running in the same issue.

Related

Moving 3D charracter - I don't want any physics, expected of collisions, and gravity

I am working on a game. I constructed my player as here: (I am using a gravity on my world)
private ArrayMap<String, GameObject.Constructor> constructors = new ArrayMap<String, GameObject.Constructor>(String.class, GameObject.Constructor.class);
private ArrayList<GameObject> instances = new ArrayList<GameObject>();
assets.load("hand.obj", Model.class);
...
model = assets.get("hand.obj", Model.class);
constructors.put("hand", new GameObject.Constructor(model, new btBoxShape(new Vector3(2.5f, 7.5f, 2.5f)), 1f));
...
hand = constructors.get("hand").construct(); // that construct method returns me model, shape and constructions.. the GameObject extends ModelInstance, so i can use it like a modelinstance
hand.transform.setToTranslation(x, y, z);
hand.body.proceedToTransform(hand.transform);
hand.body.setUserValue(instances.size());
hand.body.setCollisionFlags(hand.body.getCollisionFlags()| btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
world.addRigidBody(hand.body);
hand.body.setContactCallbackFlag(OBJECT_FLAG);
hand.body.setContactCallbackFilter(OBJECT_FLAG);
Then, in render method I am moving it:
if (!hand.body.isActive()) hand.body.activate();
if (Gdx.input.isKeyPressed(Keys.W)){
hand.body.translate(new Vector3(0,0,-1));
}
else if (Gdx.input.isKeyPressed(Keys.S)) {
hand.body.translate(new Vector3(0,0,+1));
}
That's nice! The moving now works good, when I am moving at the flat ground. Whenever there is an object before me, it is not as expected. Because my player shape is biger than
object shape (which is 2.5f, 2.5f, 2.5f), it kind of falls on it. So I would like to set the rotation to be still the same, so the object will not be rotating (so it will not "fall" on the object before). And so I tried to do it, and I failed. Because there are functions like rotate, and I want to something like setRotation
. And so, there is a setToRotation, but you can not pass there a Quaternion.
I need help. I tried to use a btKinematicCharacterController but it was bad. The ghostObject every time falled through object, but the objects got a collision from him.
and so I want to create a player movment, like in games like Wow, minecraft, and so on.
I looked at the btKinematicCharacterController again. The reason why my ghostobject falled through the ground was. Generally, I don't know the reason: D probably I was using another broadphase for ghost, that for world. This line fixes it: characterController.setUseGhostSweepTest(false);
and I am getting another problem, when I am walking on my ground (a lot of objects), the character is getting to lesser Y position. I don't know why.
Here is my construction:
btPairCachingGhostObject ghostObject;
btConvexShape ghostShape;
btKinematicCharacterController characterController;
Vector3 characterDirection = new Vector3();
Vector3 walkDirection = new Vector3();
...
ghostObject = new btPairCachingGhostObject();
ghostObject.setWorldTransform(hand.transform);
ghostShape = new btCapsuleShape(5f, 0.5f);
ghostObject.setCollisionShape(ghostShape);
ghostObject.setCollisionFlags(btCollisionObject.CollisionFlags.CF_CHARACTER_OBJECT);
characterController = new btKinematicCharacterController(ghostObject, ghostShape, .00001f);
// And add it to the physics world
characterController.setUseGhostSweepTest(false);
world.addCollisionObject(ghostObject,
(short)btBroadphaseProxy.CollisionFilterGroups.CharacterFilter,
(short)(btBroadphaseProxy.CollisionFilterGroups.StaticFilter | btBroadphaseProxy.CollisionFilterGroups.DefaultFilter));
world.addAction(characterController);
... (in render - moving)
if (!load)
{
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
hand.transform.rotate(0, 1, 0, 5f);
ghostObject.setWorldTransform(hand.transform);
}
if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
hand.transform.rotate(0, 1, 0, -5f);
ghostObject.setWorldTransform(hand.transform);
}
// Fetch which direction the character is facing now
characterDirection.set(-1,0,0).rot(hand.transform).nor();
// Set the walking direction accordingly (either forward or backward)
walkDirection.set(0,0,0);
if (Gdx.input.isKeyPressed(Keys.UP))
walkDirection.add(characterDirection);
if (Gdx.input.isKeyPressed(Keys.DOWN))
walkDirection.add(-characterDirection.x, -characterDirection.y, -characterDirection.z);
walkDirection.scl(4f * Gdx.graphics.getDeltaTime());
// And update the character controller
characterController.setWalkDirection(walkDirection);
// And fetch the new transformation of the character (this will make the model be rendered correctly)
}
world.stepSimulation(delta, 5, 1f/60f);
if (!load)
ghostObject.getWorldTransform(hand.transform);
How to fix this?
I set up the debugDrawer, so i was able to see the shapes of the bullet objects.. and my problem was that: the ghostObject(charController) was pushing my objects down.. Although my objects were static. So i set the mass of the objects to 0 and problem is fixed. But I still dont know, how it could push static objects. But i dont care. :)
EDIT: i will accept this answer in 2 hours, because now i cant.

function 'for - do - end" / moving object ( Corona Sdk )

I'm beginner for coding, I've questions :
First I'd like know why that code is not moving :
local speed = 5
function cube ()
for i = 1,20,2 do
local rect = display.newRect(50,50,50,50)
rect.x = screenleft-300 + (50*i)
rect.y = _y
rect.x = rect.x - speed
if (rect.x < -450 )then
rect.x = 1200
end
end
end
timer.performWithDelay(1, cube, -1)
Secondly : What's the difference between
Runtime:addEventListener( "enterFrame", cube )
and
timer.performWithDelay(1, cube, -1)
Because I get the same result with both of them
And to be done, Why when I use the function "for" to duplicate something like the square i've done upside, this one put the image behind eachother and not like the square beside eachother ( the image i'm trying to duplicate has more than 4 side )
Thanks for all your reply !
thks a lot dude , I know what you mean by here but my question is little bit weird maybe lol and maybe we can't do it
I try to explain again :
for i=1,10,1 do
local Circle = display.newCircle(50, 20, 20)
Circle.x = _x + (50*i)
Circle.y = _y
end
So here I've a Circle line like that 00000 (imagine 0 are circle ^^)
and I want to make that line moving from the left to the right screen, but when i try to make it move with :
Circle.x = Circle.x - speed
Corona don't recognize the " circle.x " so I can't, maybe because is insert into the"FOR"
SO my question is : "How to move this Circle line if that's possible with the "FOR" ?
I hope I've Been clearer
Anyway, Thanks for all
I'll answer your second question first:
Runtime:addEventListener( "enterFrame", cube )
The function addEventListener adds a listener to the object’s list of listeners. When the named event occurs (in this case "enterFrame"), the listener will be invoked and be supplied with a table representing the event. In your code, the listener will call cube() on every frame (normaly, games run at 60 frames per second).
timer.performWithDelay(delay, listener [, iterations])
performWithDelay does what it says it does: Call a specified function after a delay. The timer function returns an object that can be used with other timer.* functions. In your code timer.performWithDelay(1, cube, -1) the function is calling cube() every 1ms and it is going to do so forever. This is not a good thing to do. There's nothing catching the return of the timer function and it is going to be running forever.
Now, to answer your main question. I believe what you are trying to do is create a square an move it in the screen. If that's correct, here's how you should do it:
local square = display.newRect(100,100,50,50)
local speed = 2
-- called every frame
local function moveSquare()
square.x = square.x + speed
end
Runtime:addEventListener("enterFrame", moveSquare)
The reason your code doesn't do what you want it to do is because you misunderstood a some basic CoronaSDK things.
Hope this little code helps you to understand more about how CoronaSDK works. Don't forget to check the documentation of Corona in http://docs.coronalabs.com/
You're creating an object locally in a loop and trying to move it outside of the loop. This doesn't work due to the way lua uses local variables. See http://www.lua.org/pil/4.2.html for more info about this.
Also, you'll need to place the objects into a single display group in order to move them easily. If you're using Box2D physics at all, I recommend reading up on it more at http://docs.coronalabs.com/api/library/physics/index.html.
Your code:
for i=1,10,1 do
local Circle = display.newCircle(50, 20, 20)
Circle.x = _x + (50*i)
Circle.y = _y
end
Should Be Changed to:
local Circle = display.newGroup(); --Forward declaration of Variable. Place this before any calls for it.
local speed = 2;
for i=1,10,1 do
local object = display.newCircle(50,20,20);
object.x = _x + (50*i);
object.y = _y;
Circle:insert(object); --Insert this local object into the display group
end
function moveCircle()
Circle.x = Circle.x + speed;
end
Runtime:addEventListener( "enterFrame", moveCircle);
This will move the Circle line every frame, on the X-axis, by the speed variable's value.
If you're trying to move it with a for-loop, then we'd need to see more of you code in context.

function with transition.to() does not work

local rect = display.newRect(100, 100, 100, 100)
local moving, moving2
function moving()
transition.to(rect, {time=500, x=300, y=100, onComplete=moving2})
end
function moving2()
transition.to(rect, {time=500, x=100, y=300, onComplete=moving})
end
Hi everyone. I'm a newbie to Lua, so I would like know why my rectangle is not moving on my screen with this function? When I use only this code below, it moves but stops at the end. I'd like it to repeatedly move from one side to the other:
local rect = display.newRect(100, 100, 100, 100)
transition.to(rect, {time=500, x=300, y=100, onComplete=moving2})
You need to call one of the functions. Just put:
moving()
as the last line.
Like they said, it's not moving because you don't call
moving()
or
moving2()
in your code.
Just so you know, you don't have do this complicated stuff with two different functions in the onComplete parameter. You can have the same effect on your object with one transition by changing it's easing function and setting the iterations parameter to -1 for an infinite loop.
Here is a list of the available easing functions : http://docs.coronalabs.com/api/library/easing/index.html, as you can see the easing.continuousLoop function will do what you want.
You can try something like this instead :
local rect = display.newRect(100, 300, 100, 100)
transition.to(rect, {
time = 500,
x = 300,
y = 100,
iterations = -1,
transition = easing.continuousLoop,
})
after putting at the end
moving()
it works fine. already tested it. or you may start by
moving2()
thanks everyone, it works well putting moving () at the end
I've tried quickly the last code with easing.continuousLoop but it was not working exactly as i want, but i gonna check it deeply later because it could be helpful
Anyway thanks all
Oh man, using a local object and calling it from both transitions is at some point going to cause a serious error, using your existing code pass the "rect" to each transition so it doesn't get nabbed by "still in transition."
local rect = display.newRect(100, 100, 100, 100)
local moving, moving2
function moving(inObj)
if (inObj == nil) then inObj = rect end
transition.to(inObj, {time=500, x=300, y=100, onComplete = function(iObj)
moving2(iObj)
end})
end
function moving2(inObj)
transition.to(inObj, {time=500, x=100, y=300, onComplete, onComplete = function(iObj)
moving(iObj)
end})
end
OR
if you just want to be lazy :)
local rect = display.newRect(100, 100, 100, 100)
local movingIndex = 0
local moveData = {
{time = 500, x = 300, y = 100},
{time = 500, x = 300, y = 100}
}
function MoveObject(inObj)
movingIndex = movingIndex + 1
if (movingIndex > #moveData) then movingIndex = 1 end
transition.to(inObj, {tag = "movingObjects", time=moveData[movingIndex].time, x=moveData[movingIndex].x, y=moveData[movingIndex].y, onComplete = function(iObj)
MoveObject(iObj)
end})
end
MoveObject(rect)
That way you just have one function and can just add animation points to the moveData table :)
By tagging the transition with tag = "movingObjects" we can pause and resume any running transition with just one call like transition.pause("movingObjects") or cancel etc. useful when you want to pause and/or are moving to another see without having to wait for a transition to end or by wrapping it in a pcall()
Just food for thought :)
btw:: I didn't test the code above I just wrote it in this editor so may have 1 or two things that need tweeeking.

Check If animation is running in cocos2d-x

I am currently learning cocos2D-x and am doing some sprite animation.
My Objective is that when a button is clicked the object moves to left with some animation.
Now if you click multiple times rapidly the animation takes place immediately and it looks like the bear is hoping instead of walking.
The solution to it looks simple that I should check if animation is already running and if running the new animation should not take place.
The following is a part of my code.
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("AnimBear.plist");
CCSpriteBatchNode* spriteBatchNode = CCSpriteBatchNode::create("AnimBear.png", 8);
this->addChild(spriteBatchNode,10);
CCArray *tempArray = new CCArray();
char buffer[15];
for (int i = 1; i <= 8 ; i++)
{
sprintf(buffer,"bear%i.png", i);
tempArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(buffer));
}
CCAnimation *bearWalkingAnimation = CCAnimation::create(tempArray,0.1f);
startAnimation = CCSprite::createWithSpriteFrameName("bear1.png");
startAnimation->setPosition(ccp (350 , CCDirector::sharedDirector()->getWinSize().height/2 -100));
startAnimation->setScale(0.5f);
startAnimation->setTag(5);
//Animation for bear walking
bearAnimate = CCAnimate::create(bearWalkingAnimation);
Here bearAnimate is a global variable and i wish to know if its currently playing the animation.
How do I do it.?Thank you.
Assume the Sprite that runs the action is
CCSprite* bear;
I think you can use something like
bear->numberOfRunningActions()
numberOfRunningActions( ) returns an unsigned integer, so to check if there are no actions, you would have to check if it returns 0
if ( bear -> numberOfRunningActions( ) == 0 ) {
CCLOG( "No actions running." );
} else {
CCLOG( "Actions running." );
}
The bearAnimate (CCAnimate) has a method to check that.
if (bearAnimate.isDone())
doWhatYouWant();
The method is inherited from CCAction. Good luck.

Flex-AS3 weired issue with Point

I was trying to convert global coordinates to local coordinates of a UIComplenent in my flex project using below code using below code
var gp:Point = new Point(e.stageX,e.stageY); //global point
var lp:Point = uic.globalToLocal(gp); //local point
uic is UIComponent in which I have subclass of Sprite for drawing something
I have set the sprite's mouseEnabled and mouseChildren to false to not interrupt the mouse event.
above code is within uic's mousemove event where I was tracing the gp and lp gp was giving correct value and suprisingly lp was giving negetive values. when I move the move to the top left corner of uic i expect lp to be 0,0 but it is giving the -width of of uic. I broke my head for hours and ended up finding an alternate by using offsets. Infact my original code was much simpler like this which was same issue
var lp:Point = new Point(e.localX,e.localY);
I am not sure what exactly is causing this problem. the workaround had lot of issues and it creating a mess in my rest of the algorithms.
Just now I found even more interesting thing (which is actually weird). for some reason I went and create a new lp2
var lp2:Point = new Point(e.localX,e.localY);
now surprisingly it was giving correct values as expected and I went back and changed the code as
var gp:Point = new Point(e.stageX,e.stageY); //global point
var lp:Point = uic.globalToLocal(gp); //local point
var lp2:Point = new Point(e.localX,e.localY);
var lp2:Point = uic.globalToLocal(gp);
now it is expected to have all the lp, lp2 and lp3 variables to be same but weiredly lp two is giving wrong value and lp2 and lp3 were giving correct. I am suspecting using the variable lp has something to do. I am not sure about that but above proves it so right now I am using lp2.
does any one know why is this behavior? is it a bug? or am I overseen something?
Admittedly, I didn't look at your previous questions before leaving my comment :) I take it your questions seem to leave people quite perplex... It's probably due to the way you present them as totally abstract behaviors.
Taking the example above, I'm not sure you're going the right way about the globalToLocal method.
My understanding of globalToLocal is that given a Point and a DisplayObject, globalToLocal will return the position of the Point in relation to the DisplayObject.
var pt:Point = new Point ( 10, 20 ); // x, y in relation to the Stage
var shape:Shape = new Shape();
shape.x = 10;
shape.y = 30;
// x, y should trace 0 , 10 , which is the position of the
//point in relation to shape.
pt = shape.globalToLocal(pt );
//or if you prefer to declare a new variable
var pointToShape:Point = shape.globalToLocal(pt );
In your example you state that you're trying to get the local coordinates of uic , your UIComponent , when in fact you're only returning the values of your Mouse position in relation to uic. Then you state:
"now it is expected to have all the lp, lp2 and lp3 variables to be the same "
No , because you keep redeclaring your variables:
var lp2:Point = new Point(e.localX,e.localY);
//the next declaration/statement cancels the previous one
var lp2:Point = uic.globalToLocal(gp);
Please note that once a variable has been declared , it is not necessary to redeclare it in subsequent statements. In the example above , there's no relationships between the two lp2 declaration, you may as well write:
var x:int = 10;
x = 20;
x = whatever;// each statement practically cancels the previous one.