This might be related not to the particle system but more on layering, but... i have the following code for the particle system:
CCParticleExplosion *explosion = [[CCParticleExplosion alloc] init];
explosion.texture = [[CCTextureCache sharedTextureCache] addImage:#"blah.png"];
explosion.position = ccp(100,100);
[explosion setAutoRemoveOnFinish:YES];
[explosion setTotalParticles:10];
[self addChild:explosion];
[explosion autorelease];
and it renders fine if i stick that code in like a "HelloWorld" scene. However, if i put the code under a CCLayer, and i add that CCLayer to the "HelloWorld" scene, the particles don't show up. Why is that? (i see the CCLayer just fine)
the only noticeable difference is that in my "HelloWorld" scene, i have a "world" object. and i even tried to add in [self scheduleUpdate] in my CCLayer.
in my CCLayer, i also have a blank update. am i supposed to do something here?
-(void) update:(ccTime)delta{
}
any help, including good general practice (esp memory management) would be greatly appreciated. (just starting out cocos/iOS dev) Thanks!!
Check that:
texture isn't nil
texture isn't too big (max 512x512)
texture has power of two dimensions (4, 8, 16, 32, etc)
duration is positive (otherwise it would auto remove the effect)
self.visible == YES
(self.position + explosion.position) == somewhere on the screen (explosion's position is added to self's position since its position is relative to its parent)
Related
I am writing a game in which the user must prevent falling objects (rocks) to pass the button of the screen using some plates, each click make a plate at that position but he can only have 5 plates at each time and clicking on sixth point vanished the first plate while creating a new one.
That was a brief on how my game mechanics work.
Here is the part of my code that counts falling objects(sprites) using physics and if they became more than 10 a game over message will be shown and the code restarts the game, a new game. to have a new game I need to
-(void)didSimulatePhysics
{
[self enumerateChildNodesWithName:#"rock" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.y < 0)
{
ScoreNum++;
[node removeFromParent];
score.text = [NSString stringWithFormat:#"%# %li",ScoreMSG,(long)ScoreNum];
if (ScoreNum > 10)
{
score.fontSize = 40;
score.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
score.text = #"Game Over!";
SKScene *spaceshipScene = [[GameScene alloc] initWithSize:CGRectMake(0, 0,CGRectGetMaxY(self.frame),CGRectGetMaxX(self.frame)).size];
printf("%f %f",CGRectGetMidX(self.frame),CGRectGetMidX(self.frame));
SKTransition *doors = [SKTransition doorsOpenVerticalWithDuration:0.25];
[self.view presentScene:spaceshipScene transition:doors];
ScoreNum = 0;
}
}
}];
}
GameScene is subclassed from SKScene like this
#import <SpriteKit/SpriteKit.h>
#interface GameScene : SKScene
#end
The code works find but the plates (all of the sprites on the screen) gets squeezed from sides
The following picture shows the results, first time, second time and third time, I needed 10 reputation to include 3 pictures so I had to merge them all into one picture, Here it is.
https://www.imageupload.co.uk/images/2015/08/30/123.png
Sorry, looks like I can not embed an image since I have not enough reputation!
Why each my scene squeezes?
Looks like you set a scaleMode in your viewController.viewDidLoad that handles your game scene, nothing wrong with your physics code (in your question).
look for something like this scene.scaleMode = SKSceneScaleModeAspectFill usually SKScenes are automatically scaled based on the screen size of the device and it is upto SKScene to provide you a scene.
Your scenes in your pictures shows that scenes have a complete and full cover but they are scaled.
It is kind of hard to handle sprite size while do not controling scale. I suggest to get ride of every Scale Mode and remark them all and control the scale your self.
if you are not going to zoom in/out as I believe it is the case in your game you just need to reset the scenes scale to 1 each time after each scene transition.
all.
I am now developing an ios game using sprite kit.The game mechanics include: infinitely scroll sprites from top to bottom.
My game scene holds just 3 sprites,top,middle,bottom.
I have dozens of sprite images,so my solution is dynamic create 3 sprites ( so the sprites can fill the whole screen),when the bottom sprite is off screen,then destroy it;when the top sprite
goes down the top frame,create a new sprite node,then exchange the bottom,middle,top sprite.
The pseudo code:
in the interface file:
- GameScene:SKScene
{
...
SKSpriteNode *_topSprite;
SKSpriteNode *_middleSprite;
SKSpriteNode *_bottomSprite;
...
}
in the implementation file:
- (void)update:(CFTimeInterval)currentTime
{
// 1 compute time interval
// 2 update sprite node
_topSprite.position move down 100*timeInterval
_middleSprite.position move down 100*timeInterval
_bottomSprite.position move down 100*timeInterval
// 3 crop the off-screen bottom sprite node
if (_bottomSprite is offScreen)
{
[_bottomSprite removeFromParent]
}
// 4 check the highest sprite position visible
// if the highest position is below the frame top,then create new sprite
_bottomSprite = _middleSprite;
_middleSprite = _topSprite;
_topSprite = [self createNewNode]; // random a sprite image
}
the game fps is 60,and the nodes counts is not increasing.
All seems good,but i found sometimes the game just suddenly has a very shot choke causing the moving frame not continuous.
In my instinct,I thought the main reason is caused by step 4.
But I don't have any idea to solve it.
Any suggestions will be appreciated.
Here is the createNewNode method:
- (SKSpriteNode *)createNewNode {
NSString *blockName = [self randomImageName];
SKSpriteNode *sprite = [[SKSpriteNode alloc] initWithImageNamed:blockName];
sprite.position = _highestPosition;
sprite.anchorPoint = CGPointMake(0.5, 0);
NSLog(#"putAnotherNodeOnTop %#", blockName);
[self addChild:sprite];
return sprite;
}
A couple of suggestions.
Since you are using the same three images, you don't need to re-create the sprites each time. It should be less expensive to set the hidden value to YES, move the sprite somewhere, set the texture and then show it again with hidden to NO. SpriteKit doesn't draw hidden nodes, or ones off screen.
Your code basically asks for a PNG on disk every frame in update when createNewNode: is called. It should be more performant to load the textures in memory and assign them to sprites as needed. If you have just a few, making them SKTexture instance variables would be an easy way to do it.
Use spritesheets (texture atlases), it is much faster to draw an image from memory at mapped coordinates than to load it from disk each time. For example with three images in a spritesheet this can be a single draw call. From disk this is three separate draw calls.
You are returning a sprite and adding it to the scene in the createNewNode: method. Maybe that is what you want for some reason. It stood out as possible duplicate effort.
In viewWillAppear I want to adjust some of my views using the following transformation (Monotouch code):
CATransform3D oTransform3D = CATransform3D.Identity;
oTransform3D.m34 = 1.0f / -400;
oTransform3D = oTransform3D.Translate( 110, 0, 0);
oTransform3D = oTransform3D.Rotate( (-70f) * (float)Math.PI / 180f, 0, 1, 0);
However, this causes the view to be rendered far left of the screen.
If I put the very same code in viewDidAppear, it is working.
I have already checked that all views have valid sizes.
Did you ever figure this out? I've run into a similar situation where a 3D transform refuses to behave when applied to an immediate subview of a UIViewController's root view. A workaround for me was to wrap the subview in another container UIView.
Something along these lines:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)];
container.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoResizingFlexibleHeight;
[self.view addSubview:container];
self.myCrazyFlippingSpinningView = [[CrazyFlippingSpinningView alloc] init];
[container addSubview:self.myCrazyFlippingSpinningView];
}
Of course, I'd prefer to not have to do that. It's such a hack. If anyone's encountered this and has a better solution, I'd love to see it.
Thanks!
Not sure I fully understand the question but I am going to take a swag.
CATransform3D has a vanishing point that transforms refer to. The vanishing point is always the x,y center point of whatever view you place the transformed view onto. When I was struggling through the 3D transform issues and getting unexpected results, it was always solved by simply making sure I knew the size and center point of the container view.
You say your code works in ViewDidLoad...does that mean you are adding a transformed view to the base view? like: this.View.AddSubview(yourTransformedView); ??
I mean, I don't think your problem is a matter of ViewWillAppear vs. ViewDidLoad; I am going to guess that if I saw the code where you apply your transform to the views and then add your views to a base view or some other superview, I would be able to quickly tell you what is happening.
I need to draw a waveform in an NSView. (I have all the samples in an array). The drawing must be efficient and really fast without clipping, flickering, etc, it must be smooth. The waveform will be "moving" according to the song position and some changes to the samples (DSP processing) will be shown as visual representation onto NSView in realtime.
I'm familiar drawing lines, arcs, etc onto canvas objects and I have developed apps doing such things but not on Mac OS X ...
I want to ask if anyone can guide me where to start drawing! Core Animation, OpenGL, simple override drawing methods, ??, etc. Which would be the best practice - API to use?
I would keep it simple and create an NSView subclass with an audioData property that uses Cocoa drawing. You could call [view setAudioData:waveArray] which would in turn call [self setNeedsDisplay:YES].
In your drawRect: method you could then iterate through the samples and use NSRectFill() accordingly. Here sample's value is between 0 and 1.
- (void)drawRect:(NSRect)dirtyRect {
[[NSColor blueColor]set];
for (id sample in self.waveArray) {
NSRect drawingRect = NSZeroRect;
drawingRect.origin.x = [self bounds].origin.x;
drawingRect.origin.y = [self bounds].origin.y + ([self.waveArray indexOfObject:sample]/([self.waveArray count] - 1.0));
drawingRect.size.width = [self bounds].size.width/[self.waveArray count];
drawingRect.size.height = [self bounds].size.height * [sample value];
NSRectFill(drawingRect);
}
}
This code isn't exact, and you should be sure to make it more efficent by only drawing samples inside dirtyRect.
I would start with a really long and thin image to represent a single bar/column for the waveform.
My plan would be to have a NSTimer that moves all bars of the wave one to the left every 0.01 seconds.
So something like this in the loop.
for (int x; x < [WaveArray count] ; x++)
{
UIImageView * Bar = [WaveArray ObjectAtIndex: x];
[Bar setCenter:CGPointMake(Bar.center.x-1,Bar.center.y)];
}
Now all you have to do is create the objects at the correct hight and add them to the WaveArray and they all will be moved to the left.
I'm trying to make an ipad application that draws alot, but I really mean alot of lines on stage (10.000+)
using this simple forloop, my ipad crashes after 40~60 seconds (without showing result)
for ( int i = 0; i < 10000; i++ )
{
int r_x = rand() % 750;
int r_y = rand() % 1000;
CGPoint pointpoint = CGPointMake(r_x, r_y);
UIColor *st = [[GetColor alloc] getPixelColorAtLocation:pointpoint];
DrawLine *drawview = [[DrawLine alloc]initWithFrame:CGRectMake(r_x, r_y, 20, 20) selectedcolor:st];
[self.view addSubview:drawview];
[drawview release];
[DrawLine release];
[GetColor release];
}
and this is my "DrawLine" class:
- (id)initWithFrame:(CGRect)frame selectedcolor:colors{
if ((self = [super initWithFrame:frame])) {
selectedcolor_t = colors;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)drawRect:(CGRect)frame{
CGContextRef c = UIGraphicsGetCurrentContext();
float* colors = CGColorGetComponents(selectedcolor_t.CGColor);
CGContextSetStrokeColor(c, colors);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 0.0f, 0.0f);
CGContextAddLineToPoint(c, 20.0f, 20.0f);
CGContextStrokePath(c);
}
how can I solve this problem? How can I draw this much subviews without crashing the iOS?
thanks so much!! :)
Please reconsider what you are doing there:
In line 4 of your loop, you alloc an instance of GetColor — which you never use again. Ask yourself: Does that make any sense from a design point of view?
In that same line, if you don't violate Cocoa's naming-conventions, you create a UIColor that is never released...
Then in line 8 you release the class-object of DrawLine (ditto that for the next line and the GetColor-class). This is terribly, horribly wrong!
Please visit the Memory Management Programming Guide at the iOS Dev-Center and read the first two sections (again)!
Besides that, re-evaluate your design:
Should GetColor really be a class, so that you create instances? Wouldn't a simple helper-function for color interpolation make more sense in this context?
If it should be a class, why not create just one instance of it outside of the loop and simply query it repeatedly for the colors?
Do you really need a subclass of UIView to draw a single straight, solid, single-colored line? If the lines need not be updated, you should (as Richard and nacho4d suggested) draw all of them in one object (e.g. by a custom UIView or by a delegate of CALayer implementing the drawLayer:inContext: method). If you need to update those lines later, you could simply (ab)use CALayer...
In the latter case, your problem then becomes:
Calculate your random coordinates.
Calculate your color.
Create an opaque CALayer with
a) that color as its backgroundColor,
b) a width of 20 * sqrt(2),
c) a height of whatever-you-want-to-be-the-width-of-that-line,
d) your point as its origin and
e) a rotation of 45.
Add that layer as a sublayer to self.view's layer.
Cheers
Daniel
If your lines are static (not moving later, not animating, etc) , as they seem to be, you could also draw all the lines in a single drawRect: in one view without creating 1000 of CALayers.
I can't tell if this is faster than drawing 1000 CALayers (because CoreAnimation is hardware accelerated and CoreGraphics is not) but it's surely lighter since all the lines will be flattened in a single bitmap. (which is the context of your view)
Just move your for loop inside your drawRect: and follow danyowde advices.( you just need one color object or a helper function but not to create a color each iteration)
Good luck, Hope it helps;)