How to move/animate CGRects - ios

I'm having trouble moving CGRects around. I'm trying to make a breakout game. In my drawView file, I have written code in the drawRect function by removing the comments.
I end my drawRect function with this moveBall(&_ball, &_context, rect);
moveball() is declared/implemented in my viewController.h/viewController.m.
I'm not sure how to then move/animate the ball once it is in my controller. I have the following code:
void moveBall(CGRect *ball, CGContextRef *context, CGRect rect)
{
CGFloat velX = 1;
CGFloat velY = 1;
while (ball->origin.x + CGRectGetWidth(*ball) < CGRectGetWidth(rect))
{
CGContextClearRect(*context, *ball);
*ball = CGRectOffset(*ball, velX, velY);
CGContextFillEllipseInRect(*context, *ball);
}
};
What happens is that the ball is "moved" to a different place, not animated there. The problem is that the while loop is implemented and the final result is displayed. I want the while loop to run after the drawing is done.
Can anyone guide me to make the ball move?

Trying to make animations inside the drawRect method using CoreGraphics framework is exercise in futility.
For animations you should use other frameworks/technologies intended for that.
Standard apps - Core Animation
Games - SpriteKit, OpenGL ES, Metal, cocos2D, Unity3D,

Related

Detecting when SKSpriteNode is completely below another SKSpriteNode

For a game I'm creating, an SKSpriteNode gradually makes its way down the user's screen. There's another SKSpriteNode (position is static) near the bottom of the screen, leaving only a little bit of space for the original SKSpriteNode to fit in. I need to detect when the first SKSpriteNode is COMPLETELY below the second SKSpriteNode, which I'm having a bit of trouble with. Here's the code I'm currently using:
if (pos.y > barPosY) //pos.y = 1st SKSpriteNode, barPosY = 2nd SKSpriteNode
{
touchedTooEarly = true
}
For some reason, when the first SKSpriteNode goes just a little bit over the 2nd SKSpriteNode (not all the way), it still detects it as being completely over. Is there a coordinate space issue I'm missing?
The logic
A sprite a covers a sprite b if
b.frame is inside a.frame
b.zPosition is below a.zPosition
The extension
Now let's build an extension
extension SKSpriteNode {
func isCoveredBy(otherSprite: SKSpriteNode) -> Bool {
let otherFrame = CGRect(
origin: convertPoint(otherSprite.position, fromNode: otherSprite),
size: otherSprite.frame.size
)
return zPosition < otherSprite.zPosition && CGRectContainsRect(frame, otherFrame)
}
}
Problem #1: transparency
This mechanism totally ignores transparency.
Problem #2: same sprite
If you compare 2 sprites of the same type the function CGRectContainsRect will return true only when they are exactly aligned. Althoug you can solve this problem creating a smaller rectangle when you compare the sprites.

cocos2d ccDrawSolidPoly in a CCRenderTexture sometimes creates a blank asset (possible race condition)

I have a function intended to create a trapezoidal polygon CCSprite. 99% of the time, the function works fine. The other 1%, it creates a completely blank sprite (though, of the correct dimensions). Here's my function:
- (CCRenderTexture*)createPolygon {
CGFloat bottom = [self bottomCrop];
CGFloat top = self.contentSize.height - [self topCrop];
CGFloat constrict = PERSPECTIVE_CONSTRICT_PX_FOR_HEIGHT(top);
CCRenderTexture * rt = [CCRenderTexture renderTextureWithWidth:self.contentSize.width
height:self.contentSize.height];
[rt begin];
CGPoint pts[] = { ccp(0,bottom),
ccp(constrict,top),
ccp(self.contentSize.width-constrict,top),
ccp(self.contentSize.width,bottom) };
ccDrawSolidPoly(pts, 4, ccc4FFromccc3B(self.backgroundColor));
[rt end];
#if TARGET_IPHONE_SIMULATOR
[rt saveToFile:#"terrain.jpg"];
#endif
return rt;
}
As you can see, I'm saving the RenderTexture to a file so that I can compare good vs. bad output. As I said above, the dimensions of the files are the same, but in the edge case the polygon is simply missing from the output.
I'm guessing I have some sort of race condition with another function (perhaps ccDrawSolidRect is drawing into the wrong context...?), but I have no idea where it might be. Is there any way I can protect against this?
edit FWIW, I'm positive that self.backgroundColor is not white/transparent, so that should not be the problem. Similarly, I'm sure that bottom and top are non-zero. These values are all coded as switch statements, based upon some configurations.

endless running vertical cocos2d

Follow question/answers here, I'm able to create an infinite vertical scroll already, but just for one background image.
Now I move to a new problem.
I have multi background frame image, like 7 frames to complete a background scroll animation.
I can run animation as an endless animation aswell just follow this:
-(void)scrollBackground:(ccTime)dt
{
timeWaited+=dt;
if (timeWaited<FRAME_RATE) {
return;
}
timeWaited = 0;
bgIndex++;
if (bgIndex == 7) {
bgIndex = 0;
}
CCSprite* bgSprite = bgSprites[bgIndex];
bgSprite.zOrder = LAYER_BACKGROUND;
}
But it look very jerky and actually dont look like it's running forward,
I think i may need to scroll each sprite a little before replace it with new sprite,
Or may be i need to zoom each sprite a bit to fit new sprite

Jumpy CADisplayLink Animation

As detailed in a previous post (Here), I'm creating an animation that starts at an initial angle and moves to an ending angle. I've decided to use CADisplayLink for this animation because the animation needs to run as fast as possible during user input, so a CALayer with a CAKeyframeAnimation seemed like it would be too slow to achieve this.
After implementing the CADisplayLink, which calls setNeedsDisplay, I do have the animation working, but it looks really bad because it chunks up the difference between endAngle and initialAngle into heavily visible blocks of angles instead of creating a continuous flow from one angle to the next. Here's the current code I have:
CGFloat newAngleToAnimate = animationProgress + ((endAngle-initialAngle)/kDrawDuration)*elapsedTime;
// Use newAngleToAnimate to draw in drawInContext
animationProgress = newAngleToAnimate; // Update the progress for the next frame.
Also, kDrawDuration is defined as 3.0f, so I want the animation from initialAngle to endAngle to take 3.0 seconds. I break up the full circle (2*M_PI radians) into equal segments by calculating 2*M_PI / kNumAnglesInAnimation, and preferably I want to animate one of those angles every frame, but somehow I still have to take kDrawDuration and elapsedTime into account, which I'm just not seeing how to achieve.
Thanks for any help with fixing this!
CGFloat newAngleToAnimate = animationProgress + ((endAngle-initialAngle)/kDrawDuration)*elapsedTime;
don't track "animationProgress". Your elapsedTime is all you need in order to get your animation correct. So just remove it and use:
CGFloat newAngleToAnimate = ((endAngle-initialAngle)/kDrawDuration)*elapsedTime;

I'm unable to make my sprites "Flip"

I'll start off by admitting that I am a beginner to ActionScript and I am in the process of coding my own basic arcade game (Similar to that of the old arcade game "Joust"). Whilst I have been able to code the sprite's movement I am looking to make the sprite flip to face the other way when I press the right arrow. I figured either I could try and rotate the object around its axis (Which I've tried multiple times and has proved difficult) or I could try and "Replace" the current sprite with another sprite (Which is just the sprite facing the opposite way). I've searched everywhere for a method of replacing a sprite with another sprite but to no avail. How would it be possible to give this sprite a flip effect when a certain keyCode is used?
Try this simple code below. Here 'object' is the movieclip/sprite that you want to flip
stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
function OnKeyDown(event:KeyboardEvent):void
{
var uiKeyCode:uint = event.keyCode;
switch (uiKeyCode)
{
case Keyboard.LEFT :
object.scaleX = -1; //flip
break;
case Keyboard.RIGHT :
object.scaleX = 1; //unflip
break;
}
}
NOTE: If you want the movieclip to flip without any shift in its position then the movieclip must be horizontally center registered.
Tell me if this works for you.
Are you using as2/as3? you could flip the axis Y 180 degrees
if your using as2 you will need to either mirror the bitmap via actionScript or
add a second bitmap that is mirrored to the display list.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedDown);
function keyPressedDown(event:KeyboardEvent):void
{
var key:uint = event.keyCode;
switch (key)
{
case Keyboard.LEFT :
myMovieClip.rotaionY = 180; // MC will be mirrored
break;
case Keyboard.RIGHT :
myMovieClip.rotaionY = 0;
}

Resources