I am using UIImagePickerController for users to select the background in my Cocos2D game. It works the first time you use it, but if you try to change the background again the picker will show up, but when you select the image the background will stay the same.
This is my code:
- (void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSArray *TouchesA = touches.allObjects;
for (int i = 0; i < TouchesA.count; i++) {
CGPoint touchLocation = [self convertTouchToNodeSpace:[TouchesA objectAtIndex:i]];
CGRect rect = CGRectMake(touchLocation.x, touchLocation.y, 1, 1);
if(CGRectIntersectsRect(rect, infoButton.boundingBox))
{
[self pickPhoto:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
}
}
}
-(void)pickPhoto:(UIImagePickerControllerSourceType)sourceType{
UIImagePickerController *picker = [[UIImagePickerController alloc]init];
picker.delegate = self;
picker.sourceType = sourceType;
//picker.wantsFullScreenLayout = YES;
//[picker presentModalViewController:picker animated:YES];
[[[CCDirector sharedDirector] openGLView] addSubview:picker.view];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[picker dismissModalViewControllerAnimated:YES];
[picker.view removeFromSuperview];
[picker release];
}
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info{
newImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[picker dismissModalViewControllerAnimated:YES];
[picker.view removeFromSuperview];
[picker release];
CCSprite *imageFromPicker = [CCSprite spriteWithCGImage:newImage.CGImage key:#"ImageFromPicker"];
Background = imageFromPicker;
int SSw = [CCDirector sharedDirector].winSize.width;
int SSh = [CCDirector sharedDirector].winSize.height;
Background.position = ccp(SSw/2, SSh/2);
Background.scaleX = SSw / Background.textureRect.size.width;
Background.scaleY = SSh / Background.textureRect.size.height;
[[self children] removeObjectAtIndex: 0];
[[self children] insertObject:Background atIndex:0];
}
How can I fix this?
EDIT:
#interface HelloWorldLayer : CCLayer <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>
{
CCSprite *infoButton;
CCSprite *Background;
UIImage *newImage;
}
-(id) init
{
if( (self=[super init])) {
self.isTouchEnabled = true;
[[CCDirector sharedDirector].openGLView setMultipleTouchEnabled:YES];
int SSw = [CCDirector sharedDirector].winSize.width;
int SSh = [CCDirector sharedDirector].winSize.height;
Background = [CCSprite spriteWithFile:#"B.jpg"];
Background.position = ccp(SSw/2, SSh/2);
Background.scaleX = SSw / Background.textureRect.size.width;
Background.scaleY = SSh / Background.textureRect.size.height;
infoButton = [CCSprite spriteWithFile:#"info.png"];
infoButton.position = ccp(SSw - 15, 15);
[self addChild:Background];
[self addChild:infoButton];
[self schedule:#selector(nextFrame:)];
}
return self;
}
I've had the same problem
Check this line:
CCSprite *imageFromPicker = [CCSprite spriteWithCGImage:newImage.CGImage key:#"ImageFromPicker"];
and try to replace it with:
// resize image
UIImage* image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// add current shot
CCTexture2D *texture2D = [[[CCTexture2D alloc] initWithImage:image] autorelease]; // this is new
CCSprite *sprite = [CCSprite spriteWithTexture:texture2D]; // this is new
also look here:
http://www.cocos2d-iphone.org/forum/topic/30259?replies=8#post-149117
Hope this helps.
How about trying something like:
[Background removeFromParentAndCleanup:YES];
CCSprite *imageFromPicker = [CCSprite spriteWithCGImage:newImage.CGImage key:#"ImageFromPicker"];
Background = imageFromPicker;
int SSw = [CCDirector sharedDirector].winSize.width;
int SSh = [CCDirector sharedDirector].winSize.height;
Background.position = ccp(SSw/2, SSh/2);
Background.scaleX = SSw / Background.textureRect.size.width;
Background.scaleY = SSh / Background.textureRect.size.height;
[[self children] insertObject:Background atIndex:0];
Related
I want to create walking man animation in SceneKit.
I'm exporting animated .dae files from 3DSMax + OpenCollada , I also use ConvertToXcodeCollada to combine all animations in one.
How i get animation:
SCNScene *humanScene = [SCNScene sceneNamed:#"art.scnassets/myScene.DAE"];
CAAnimation *Animation = [[humanScene rootNode] animationForKey:#"myScene-1"];
I also try to get animation from "SCNSceneSource"
How i add animation:
SCNNode *humanNode = [humanScene.rootNode childNodeWithName:#"myScene-1" recursively:YES];
[humanNode addAnimation:walkingAnimation forKey:#"myScene-1"];
or:
SCNNode* humanNode = [SCNNode new];
for(SCNNode* node in humanScene.rootNode.childNodes){
[humanNode addChildNode:node];
}
[humanNode addAnimation:walkingAnimation forKey:#"myScene-1"];
My object "walkingAnimation" is "CAAnimationGroup".
But it doesn't animate in application.
I can see animation only in Xcode sceneKit editor.
example of my .DAE file
Try the following code with your model. It works. I used Xcode 13.2.1 in macOS 12.1.
At first fill viewDidLoad method:
#import "GameViewController.h"
#implementation GameViewController
SCNView *sceneView;
bool notRunningSwitch;
NSMutableDictionary<NSString*, CAAnimation*> *animations;
SCNNode *node;
- (void)viewDidLoad
{
[super viewDidLoad];
sceneView = (SCNView *)self.view;
notRunningSwitch = YES;
animations = #{}.mutableCopy;
node = [SCNNode node];
SCNScene *scene = [SCNScene scene];
sceneView.scene = scene;
sceneView.autoenablesDefaultLighting = YES;
sceneView.allowsCameraControl = YES;
[self anime];
}
Then anime and loadAnime methods:
- (void)anime
{
SCNScene *standStillScene = [SCNScene sceneNamed:#"art.scnassets/Idle"];
for (SCNNode *childNode in standStillScene.rootNode.childNodes)
{
[node addChildNode:childNode];
}
node.scale = SCNVector3Make(0.1, 0.1, 0.1);
node.position = SCNVector3Make(0, 0,-2.5);
[sceneView.scene.rootNode addChildNode: node];
[self loadAnime:#"running" inScene:#"art.scnassets/Running" withID:#"Running-1"];
}
- (void)loadAnime:(NSString*)withKey inScene:(NSString*)scene withID:(NSString*)id
{
NSURL *url = [NSBundle.mainBundle URLForResource:scene withExtension:#"usdz"];
SCNSceneSource *source = [SCNSceneSource sceneSourceWithURL:url options:Nil];
CAAnimation *charAnimation = [source entryWithIdentifier:id
withClass:CAAnimation.self];
charAnimation.repeatCount = 1;
charAnimation.fadeInDuration = 1;
charAnimation.fadeOutDuration = 1;
[animations setValue:charAnimation forKey:withKey];
}
And at last touchesBegan:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CGPoint point = [touches.allObjects.firstObject locationInView: sceneView];
NSDictionary<SCNHitTestOption, id> *options = #{ SCNHitTestBoundingBoxOnlyKey: #(YES) };
NSArray<SCNHitTestResult *> *hitTestResults = [sceneView hitTest: point options: options];
if (notRunningSwitch == YES) {
[sceneView.scene.rootNode addAnimation:animations[#"running"] forKey:#"running"];
} else {
[sceneView.scene.rootNode removeAnimationForKey:#"running" blendOutDuration:1.0];
}
notRunningSwitch = !notRunningSwitch;
NSLog(#"%#", hitTestResults.firstObject.node.name);
NSLog(#"%f", hitTestResults.firstObject.modelTransform.m43);
}
#end
Question:
How to achieve this animation with Spritekit?
What I've done:
Problem:
1) I can draw all four petals,but once I lift my finger to draw the circle, it will still create a line from the previous point where I lift my finger to the new touches begin point. refer to gif below:
2) How to remove the solid orange line from the view incrementally (mine is too abrupt)?
3) Need to tune the .sks file properties.
4) https://stackoverflow.com/questions/29792443/set-the-initial-state-of-skemitternode
This is my code:
#import "GameScene.h"
#interface GameScene()
#property (nonatomic) SKEmitterNode* fireEmmitter;
#property (nonatomic) SKEmitterNode* fireEmmitter2;
#end
#implementation GameScene
NSMutableArray *_wayPoints;
NSTimer* myTimer;
-(void)didMoveToView:(SKView *)view {
_wayPoints = [NSMutableArray array];
//Setup a background
self.backgroundColor = [UIColor blackColor];
//setup a fire emitter
NSString *fireEmmitterPath = [[NSBundle mainBundle] pathForResource:#"magic" ofType:#"sks"];
_fireEmmitter = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath];
_fireEmmitter.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2 - 200);
_fireEmmitter.name = #"fireEmmitter";
_fireEmmitter.zPosition = 1;
_fireEmmitter.targetNode = self;
_fireEmmitter.particleBirthRate = 0;
[self addChild: _fireEmmitter];
//setup another fire emitter
NSString *fireEmmitterPath2 = [[NSBundle mainBundle] pathForResource:#"fireflies" ofType:#"sks"];
_fireEmmitter2 = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath2];
_fireEmmitter2.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
_fireEmmitter2.name = #"fireEmmitter";
_fireEmmitter2.zPosition = 1;
_fireEmmitter2.targetNode = self;
_fireEmmitter2.particleBirthRate = 0;
[self addChild: _fireEmmitter2];
//Setup a LightNode
SKLightNode* light = [[SKLightNode alloc] init];
light.categoryBitMask = 1;
light.falloff = 1;
light.ambientColor = [UIColor whiteColor];
light.lightColor = [[UIColor alloc] initWithRed:1.0 green:1.0 blue:0.0 alpha:0.5];
light.shadowColor = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.3];
[_fireEmmitter addChild:light];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];
CGMutablePathRef ref = CGPathCreateMutable();
CGPoint p = touchPoint;
p = [self.scene convertPointToView:p];
CGPathMoveToPoint(ref, NULL, p.x, p.y);
_fireEmmitter.position = CGPointMake(touchPoint.x, touchPoint.y);
_fireEmmitter.particleBirthRate = 2000;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];
//On Dragging make the emitter with the attached light follow the position
for (UITouch *touch in touches) {
[self addPointToMove:touchPoint];
CGPoint location = [touch locationInNode:self];
[self childNodeWithName:#"fireEmmitter"].position = CGPointMake(location.x, location.y);
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
_fireEmmitter.particleBirthRate = 0;
[self performSelector:#selector(userHasCompletedTheDrawing) withObject:nil afterDelay:3];
}
- (void)userHasCompletedTheDrawing{
CGMutablePathRef path = CGPathCreateMutable();
if (_wayPoints && _wayPoints.count > 0) {
CGPoint p = [(NSValue *)[_wayPoints objectAtIndex:0] CGPointValue];
//p = [self.scene convertPointToView:p];
CGPathMoveToPoint(path, nil, p.x, p.y);
_fireEmmitter2.position = CGPointMake(p.x,p.y);
_fireEmmitter2.particleBirthRate = 1000;
for (int i = 0; i < _wayPoints.count; ++i) {
p = [(NSValue *)[_wayPoints objectAtIndex:i] CGPointValue];
CGPathAddLineToPoint(path, nil, p.x, p.y);
}
SKAction *followTrack = [SKAction followPath:path asOffset:NO orientToPath:YES duration:1];
[_fireEmmitter2 runAction:followTrack completion:^{
_fireEmmitter2.particleBirthRate = 0;
[_fireEmmitter2 runAction:[SKAction waitForDuration:1] completion:^{
//_fireEmmitter2.particleBirthRate = 0;
}];
}];
}
//myTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: #selector(removePointToMove) userInfo: nil repeats: YES];
[self performSelector:#selector(removeAllPointToMove) withObject:nil afterDelay:1];
}
- (void)addPointToMove:(CGPoint)point {
[_wayPoints addObject:[NSValue valueWithCGPoint:point]];
}
- (void)removeAllPointToMove{
[_wayPoints removeAllObjects];
}
- (void)removePointToMove{
if ([_wayPoints count]>0) {
[_wayPoints removeObjectAtIndex:0];
}
}
- (void)drawLines {
//1
NSMutableArray *temp = [NSMutableArray array];
for(CALayer *layer in self.view.layer.sublayers) {
if([layer.name isEqualToString:#"line"]) {
[temp addObject:layer];
}
}
[temp makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
//3
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.name = #"line";
lineLayer.strokeColor = [UIColor orangeColor].CGColor;
lineLayer.fillColor = nil;
lineLayer.lineWidth = 3;
lineLayer.lineJoin = kCALineJoinRound; /* The join style used when stroking the path. Options are `miter', `round'
* and `bevel'. Defaults to `miter'. */
lineLayer.zPosition = -1;
//4
CGPathRef path = [self createPathToMove];
lineLayer.path = path;
CGPathRelease(path);
[self.view.layer addSublayer:lineLayer];
}
- (CGPathRef)createPathToMove {
//1
CGMutablePathRef ref = CGPathCreateMutable();
//2
for(int i = 0; i < [_wayPoints count]; ++i) {
CGPoint p = [_wayPoints[i] CGPointValue];
p = [self.scene convertPointToView:p];
//3
if(i == 0 ) {
CGPathMoveToPoint(ref, NULL, p.x, p.y);
} else {
CGPathAddLineToPoint(ref, NULL, p.x, p.y);
}
}
return ref;
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
[self drawLines];
if ([_wayPoints count]==0) {
[myTimer invalidate];
}
}
#end
This is my .sks files properties:
Concerning your first question, you need to split your CGPathRef into multiple subpaths so that no line gets drawn between the petals and the center. Use the CGPathCloseSubpath function when you are done drawing the petals so that you can call CGPathMoveToPoint and CGPathAddLineToPoint afterwards.
I already put my actual Gamescene inside the MyScene class. How can I create a menu screen even If I already put the game in the MyScene class. I tried to include the menu before the actual gamescene but that didnt work
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
if (self = [super initWithSize:size]){
SKSpriteNode *startButton = [SKSpriteNode spriteNodeWithImageNamed:#"startButton"];
startButton.position = CGPointMake(160, 300);
startButton.size = CGSizeMake(200, 200);
startButton.name = #"startButton";
[self addChild:startButton];
}
return self;
/* Setup your scene here */
self.anchorPoint = CGPointMake(0.5, 0.5);
self.physicsWorld.contactDelegate = self;
//SKSpriteNode *bgImage = [SKSpriteNode spriteNodeWithImageNamed:#""];
//[self addChild:bgImage];
self.backgroundColor = [SKColor colorWithRed:0.171875 green:0.2421875 blue:0.3125 alpha:1.0];
world = [SKNode node];
[self addChild:world];
self.physicsWorld.contactDelegate = self;
generator = [SPWorldGenerator generatorWithWorld:world];
[self addChild:generator];
[generator populate];
hero = [SPHero hero];
[world addChild:hero];
[self loadScoreLabels];
cloud1 = [SPHero cloud1];
[world addChild:cloud1];
cloud2 = [SPHero cloud2];
[world addChild:cloud2];
cloud3 = [SPHero cloud3];
[world addChild:cloud3];
cloud4 = [SPHero cloud4];
[world addChild:cloud4];
//uihui//
SKLabelNode *tapToBeginLabel = [SKLabelNode labelNodeWithFontNamed:GAME_FONT];
tapToBeginLabel.name = #"tapToBeginLabel";
tapToBeginLabel.text = #"tap to begin";
tapToBeginLabel.fontSize = 20.0;
[self addChild:tapToBeginLabel];
[self animateWithPulse:tapToBeginLabel]; // ** GETS RESET LABEL PULSING ** //
// ** PULSING TEXT ** //
SKAction *disappear = [SKAction fadeAlphaTo:0.0 duration:0.6];
SKAction *appear = [SKAction fadeAlphaTo:1.0 duration:0.6];
SKAction *pulse = [SKAction sequence:#[disappear, appear]];
[tapToBeginLabel runAction:[SKAction repeatActionForever:pulse]];
// ** PULSING TEXT ** //
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"startButton"]) {
SKTransition *transition = [SKTransition doorsOpenVerticalWithDuration:1.0];
MyScene *game = [[MyScene alloc] initWithSize: CGSizeMake(self.size.width, self.size.height)];
[self.scene.view presentScene:game transition:transition];
}
}
Basically, it's a very simple demand, but I've tried several methods and none of them works as expected. The closest functioning snippet is:
#import "ViewController.h"
#implementation ViewController
- (void)dealloc
{
[scrollView release];
scrollView = nil;
[super dealloc];
}
- (id)init
{
if (self = [super init])
{
self.title = #"Pictures";
scrollView = [[UIScrollView alloc] init];
scrollView.delegate = self;
scrollView.frame = CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width * 10, scrollView.bounds.size.height);
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.pagingEnabled = YES;
scrollView.userInteractionEnabled = YES;
scrollView.backgroundColor = [UIColor blackColor];
self.wantsFullScreenLayout = YES;
self.automaticallyAdjustsScrollViewInsets = NO;
isHidden = NO;
}
return self;
}
- (void)viewDidLoad
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[scrollView addGestureRecognizer:tapGesture];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture release];
for (int i = 0; i < 10; i++)
{
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:#"/path/to/%d.png", i + 1]];
UIImageView *imageView= [[UIImageView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width * i, 0.0f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = image;
[scrollView addSubview:imageView];
[image release];
[imageView release];
}
[self.view addSubview:scrollView];
}
- (void)tap:(UITapGestureRecognizer *)gesture
{
[UINavigationBar setAnimationDuration:1.0];
[UINavigationBar beginAnimations:#"HideTopBars" context:nil];
isHidden = !isHidden;
// [self setNeedsStatusBarAppearanceUpdate];
self.navigationController.navigationBar.alpha = isHidden ? 0.0f : 1.0f;
[UINavigationBar commitAnimations];
}
- (void)scrollViewDidScroll:(UIScrollView *)view
{
// further operation
}
- (BOOL)prefersStatusBarHidden
{
return isHidden;
}
#end
Without "[self setNeedsStatusBarAppearanceUpdate]", navigation bar does fade as expected, but texts on status bar remain visible, which I guess is because status bar takes navigation bar as it's background image and status bar itself doesn't fade; With "[self setNeedsStatusBarAppearanceUpdate]", the texts also fade, but navigation bar's animation becomes sliding in/out from the top of the screen along with fade effect. I've also tried to move "[self setNeedsStatusBarAppearanceUpdate]" into prefersStatusBarHidden, but that just made navigation bar visible forever. I believe this is not an odd demand, so I bet there're better and simpler solutions. Any idea?
I am using UIBezierPath for free hand drawing in an iPad app. I want to apply an eraser to a uibezierpath.
However, I want to only erase the drawing in its path. I cannot use the path color as the background color because I have other elements on the background.
Below is how I am creating my free hand drawings:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
lineWidths = 10;
brushPattern = [UIColor greenColor];
pathArray = [[NSMutableArray alloc]init];
bufferArray = [[NSMutableArray alloc]init];
self.multipleTouchEnabled = NO;
}
return self;
}
- (void)drawRect:(CGRect)rect {
for (NSMutableDictionary *dictionary in pathArray) {
UIBezierPath *_path = [dictionary objectForKey:#"Path"];
UIColor *_colors = [dictionary objectForKey:#"Colors"];
[_colors setStroke];
_path.lineCapStyle = kCGLineCapRound;
[_path stroke];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
myPath = [[UIBezierPath alloc]init];
myPath.lineWidth = lineWidths;
CGPoint touchPoint = [[touches anyObject] locationInView:self];
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[myPath addLineToPoint:CGPointMake(touchPoint.x, touchPoint.y)];
dict = #{#"Path": myPath, #"Colors": brushPattern};
[pathArray addObject:dict];
[self setNeedsDisplay];
[undoManager registerUndoWithTarget:self selector:#selector(undoButtonClicked) object:nil];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
Store a BOOL value for erase: BOOL _erase;
BOOL eraseButtonIsTapped = ...
if eraseButtonIsTapped {
_erase = yes;
} else{
_erase = NO;
}
When drawing:
[myPath strokeWithBlendMode:_erase?kCGBlendModeClear:kCGBlendModeNormal alpha:1.0f];
Just try this
brushPattern = view.backgroundColor;
This will draw a new line with the color what exactly behind your drawn path. And you can use the same pathArray to do this. So that later on you can implement redo/undo operations too. if you want i could explain you more on this.