I want to know that how to place camera near and far (By increasing and decreasing value of eyeZ self.camera setEyeX:0 eyeY:0 eyeZ:1]; self.camera setEyeX:0 eyeY:0 eyeZ:180];) including animation (for smoothness), as normally it provide jerky zooming.
My suggestion is creating your own subclass of CCActionInterval, say CCCameraZoomAnimation and override its update method. The main advantage of having an action, aside from being able to control the camera movement finely, is also the possibility of using this action through CCEaseOut/CCEaseIn (etc.) to obtain nice graphical effects.
CCCameraZoomAnimation would have the node whose camera you want to modify as a target and another parameter to the constructor specifying the final Z value.
#interface CCActionEase : CCActionInterval <NSCopying>
{
CCActionInterval * other;
}
/** creates the action */
+(id) actionWithDuration:(ccTime)t finalZ:(float)finalZ;
/** initializes the action */
-(id) initWithDuration:(ccTime)t finalZ:(float)finalZ;
#end
The update method is called with an argument dt which represents the elapsed time since the start of the action and would allow you to easily calculate the current Z position:
-(void) update: (ccTime) t
{
// Get the camera's current values.
float centerX, centerY, centerZ;
float eyeX, eyeY, eyeZ;
[_target.camera centerX:¢erX centerY:¢erY centerZ:¢erZ];
[_target.camera eyeX:&eyeX eyeY:&eyeY eyeZ:&eyeZ];
eyeZ = _intialZ + _delta * t //-- just a try at modifying the camera
// Set values.
[_target.camera setCenterX:newX centerY:newY centerZ:0];
[_target.camera setEyeX:newX eyeY:newY eyeZ:eyeZ];
}
You would also need to implement copyWithZone:
-(id) copyWithZone: (NSZone*) zone
{
CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] finalZ:_finalZ];
return copy;
}
and make use of startWithTarget to
-(void) startWithTarget:(CCNode *)aTarget
{
[super startWithTarget:aTarget];
_initialZ = _target.camera....; //-- get the current value for eyeZ
_delta = ccpSub( _finalZ, _initialZ );
}
Nothing more, nothing less.
Sorry if copy/paste/modify produced some bugs, but I hope that the general idea is clear.
if you increase the 'z' by 180 from the off, you are bound to get a jerky animation, try running this in an animation context loop,increasing the value over a period of time will allow you to have a smooth 'zoom'.
Related
Just getting started with iOS development, so please forgive my ignorance here. I've also searched for a while without success on this topic, but I'm sure I'm just not searching the right terms.
If I comment out the only line in this first for loop, the next for loop seems to function exactly how I expect. If I leave them both in then, I only see the CG stuff happening and the other objects sit still.
What does the transformation on the object currentGear have to do with the frame being changed on another object within the same view? Why would performing the transformation invalidate the frame change after it?
for (UIImageView *currentGear in self.imageGearCollection)
{
currentGear.transform = CGAffineTransformRotate(currentGear.transform, (90*M_PI)/180);
}
for (UIButton *currentCrate in self.buttonCrateCollection)
{
CGRect rectFrame = currentCrate.frame;
rectFrame.origin.x += 10;
currentCrate.frame = rectFrame;
}
Your question doesn't really have anything to do with Core Graphics.
The UIView Class Reference says this about frame:
Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
So what you're doing is not really allowed.
Since you're just trying to move the view, not change its size, you can do that by modifying its center property instead:
CGPoint center = currentCrate.center;
center.x += 10;
currentCrate.center = center;
I dont know how to use this metnod in my application
void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
b2PointState state1[2], state2[2];
b2GetPointStates(state1, state2, oldManifold, contact->GetManifold());
//NSLog(#"Presolving");
if (state2[0] == b2_addState)
{
const b2Body* bodyA = contact->GetFixtureA()->GetBody();
const b2Body* bodyB = contact->GetFixtureB()->GetBody();
b2Vec2 point = worldManifold.points[0];
b2Vec2 vA = bodyA->GetLinearVelocityFromWorldPoint(point);
b2Vec2 vB = bodyB->GetLinearVelocityFromWorldPoint(point);
b2Vec2 rV = vB - vA;
float32 approachVelocity = b2Dot(rV, worldManifold.normal);
if (-1.5f < approachVelocity && approachVelocity < 0.0f)
{
//MyPlayCollisionSound();
NSLog(#"Not Playing Sound");
}
else
{
NSLog(#"playing the sound");
}
}
}
How can I use this code in my HelloWorldLayer.mm Please help me...
I have a problem here, I have a scene where some bodies falls and hit a static body, edges alike, I implemented the b2ContactListener, and in my tick method Im checking for contacts and play the sound, the problem with this approach is that when a body is constantly in contact with the static body, the sound plays indefinitely overlaying the previous one, so at the end I have huge noise..
What can I do to avoid this situation?
Please help me thanks......
You just used following method into your update method and declare its object before schedule update method call.
Like in HelloWorldLayer.h
MyContactListener *contactListener;
And in HelloworldLayer.mm
Before
[self scheduleupdate];
contactListener=new MyContactListener();
world->setContactListener(contactListener);
Than this type of error not occur.
When two bodies collide, the b2ContactListener methods are called in the following sequence:
BeginContact
PreSolve
PostSolve
PreSolve
PostSolve
...etc
EndContact
So if you want to detect collision between the bodies once for each collision, use BeginContact or EndContact instead. These methods only take a single b2Contact parameter though so you might need to do away with using the oldManifold value in your calculation.
I'm trying to make a simple game and I am currently trying to make an arrow shoot out.
So far I have two functions,
-(void)ccTouchesBegan
Touches began does some math and gets a vector from the initial shooting point of arrow and the thumbpress, then passes this data into another function:
-(void)shatArrow:(CGPoint)cl:(CGPoint)nv{
}
What I want is for the shatArrow function to call a ccTime function that runs solely for the purpose of making the arrow move, and once the arrow is done with it's projection, the ccTime function will stop, and can be called again later when needed.
How would I go about this?
Schedule the update selector (ie in the init method of your class):
[self scheduleUpdate];
Then implement the update method:
-(void) update:(ccTime)delta
{
if (isArrowMoving)
{
// arrow move code here
if (arrow movement should end)
{
isArrowMoving = NO;
}
}
}
You can keep the update method running, unless you have hundreds of arrows it won't affect performance.
-(void) shootArrow:(CGPoint)cl:(CGPoint)nv
{
isArrowMoving = YES;
// other arrow movement init code here
}
Btw, it's "shoot, shot, shot" and not "shoot, shot, shat" or something like that. (I suppose you didn't ask for a #LinguisticsOverflow answer) ;)
I have a Cocos2D game with Box2D physics. In my GameScene.mm, I'm working on a method to zoom to a given scale:
-(void) zoomToScale:(float)zoom withDuration:(ccTime)duration
{
id action = [CCScaleTo actionWithDuration:duration scale:zoom];
[scrollNode runAction:action];
currentZoomLevel = zoom;
}
The problem that I'm having is that currentZoomLevel (which is used in the Scene's update() method) is set to the zoom immediately, and isn't gradually adjusted as per the animation. So while the animation is in progress, the currentZoomLevel variable is totally wrong.
I'm trying to figure out a way to have the currentZoomLevel variable match the progress of the animation as it's happening. According to the CCAction API Reference, the CCAction's update method takes a ccTime that's between 0 and 1 based on the progress of the animation (0 is just started, 1 is just finished).
How can I access this ccTime from outside of the action? I want to have something in my Scene's update method like this:
if(animating)
{
float progress = [action getProgress]; // How do I do this?
// Do math to update currentZoomLevel based on progress
}
Am I missing something obvious here, or am I going to have to subclass CCScaleTo?
You should be able to access the scale directly as it animates.
instead of
float progress = [action getProgress];
try
float current_scale = some_node.scale ;
where "some_node" is the thing you're animating/scaling.
Actually, your best bet is to use the new Cocos2D extension "CCLayerPanZoom", which handles all of this marvellously for you! It should be part of any new cocos2D install (v.1.0+).
I was wondering if anyone could help me with my program,
I have randomised my sprites into a specific set of co-ordinates.
I want one of the sprites that is at that specific co-ordinate, to be able to make them do something when they are at this random co-ordinate. The problem i am having is that i have to make a long list of if statements saying if this sprite is here do this if another sprite is here do the exact same thing.
if (red1.position.y>=0 && red1.position.y<=63) {
id r1animation = [CCMoveTo actionWithDuration:0.2 position:ccp(red1.position.x,33)];
[red1 runAction:r1animation];
}
if (red2.position.y>=0 && red2.position.y<=63) {
id r2animation = [CCMoveTo actionWithDuration:0.2 position:ccp(red2.position.x,33)];
[red2 runAction:r2animation];
}
i want to be able to say if any of the sprites are at that exact co-ordinate then move them to a point, in a short amount of code as possible. so basically grouping the sprites or something i'm not sure.
Thanks
i want to be able to say if any of the sprites are at that exact co-ordinate then move them to a point
Firstly, specify the 'hotspot' programatically:
CGPoint hotspot = ccp(32,32); // convenience macro,
//creates a CGPoint with x = 32, y = 32
You should store a reference to all your sprites in an array when you create them (you can use cocos2d's 'tagging' also, but I usually like to use an array for simplicity)
-(void)init {
//.. misc
// creating sprite returns a reference so keep it in an array
CCSprite* curSprite = [CCSprite spriteWithFile: //...etc]
[self.spriteArray addObject: curSprite];
// add all sprite references to your array
}
Now you can iterate over this array to see if any of the sprite's frames overlap the hotspot:
-(BOOL) checkAllSpritesForCollision
{
for (CCSprite *sp in self.spriteArray)
{
CGRect spriteRect = sp.frame;
if (CGRectContainsPoint(spriteRect,hotspot))
{
// run your action on sp...
}
}
// you might like to return YES if a collision happened?
}
This is a brute force method of checking whether every sprites frame contains a given point. There are many ways to skin this cat of course, but hopefully this will set you on a better path.
What you can do is to calculate the distance:
float pointX = thePoint.position.x;
float pointY = thePoint.position.y;
float pointDeltax = sprite.position.x-pointX;
float pointDeltay = sprite.position.y-pointY;
float pointDist = sqrt(pointDeltax*pointDeltax+pointDeltay*pointDeltay);
But maybe davbryns solution suits your purpose better.