Don't know if I'm over-thinking this or not.. but I'm trying to be able to adjust the sprites showing when my character is moving in different directions.
For example, if the players finger is above the character I want it to go to the 'moveUp' frame. If the players' finger is below the character I want to go to the 'moveDown' frame, otherwise stay at the 'normalState' frame.
Can someone show me an example of this? Or direct me to a good general tutorial about implementing Sprite sheets/Sprites in this sort of way.
I have gone through and used sprite sheets in demo projects but am looking to release this and want to approach it the proper and most successful way.
Thanks!!
I assume you have already made your sprite sheet and/or packed it (I like TexturePacker). The code would be something like:
...init...
//Place all sprite frames from sprite sheet into cache
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"spriteSheet.png"];
CCSpriteBatchNode *gameBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"spriteSheet.png"];
CCSprite *player = [CCSprite spriteWithSpriteFrameName:#"moveUp"];
[gameBatchNode addChild: player];
....
- (void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
CGPoint touchPosition = [player.parent convertTouchToNodeSpace:aTouch];
CGPoint touchPositionRelativeToPlayer = ccpSub(touchPosition, player.position);
if(touchPositionRelativeToPlayer.y > 0)
[player setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"moveUp"]];
else
[player setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"moveDown"]];
}
If you want other directions (W, E, NW, etc..) I would suggest you convert the touchPositionRelativeToPlayer to an angle using atan2 and determine the frame from that.
Related
we are trying to update old maze game in iOS objective-c
I don't know any thing about sprite(games) used in iOS.
I am trying to do hit n trial to move truck in maze game,
Truck image is used in CCsprite,So how to rotate truck image used in CCSprite on touch to every position.
_player = [CCSprite spriteWithFile:#"trolley_ipad.png"];
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
}
You set an (anchor) point to rotate around:
_player.anchorPoint = cpp(anchorX, anchorY);
and rotate it:
_player.rotation = 90;
I am new to game development and was wondering what is the best approach for displaying game data on screen.
I have an endless runner where the sprite collects gems and I want the total to be displayed on screen. I was looking at placing a UIView with a UILabel above the SKView and getting the label to update after each touch.
I also want a game over screen to appear at the end and was also looking at creating this using a UIView.
Is this the best approach or should all data be kept within the SKView itself?
Hopefully this makes sense.
While I don't think there is anything very wrong with using UIKit components within a SpriteKit application, I would recommend using SpriteKit's own components as much as possible.
For text I would recommend using SKLabelNode instead of UILabel.
Also, for buttons and other GUI elements, I think SKSpriteNodes would be most sufficient.
Simple functional button example:
SKSpriteNode *fireNode = [SKSpriteNode spriteNodeWithImageNamed:#"fireButton.png"];
fireNode.position = CGPointMake(fireButtonX,fireButtonY);
fireNode.name = #"fireButtonNode";//how the node is identified later
Handle touches:
//handle touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if fire button touched, bring the rain
if ([node.name isEqualToString:#"fireButtonNode"]) {
//do whatever...
}
}
I'm using Sprite Kit to create a game involving balloons. The balloon image is a long rectangle (dotted line) but I've defined a physics body around the balloon itself using a polygon (solid line). I'd like players to be able to "pop" the balloon. I'm using the following block of code to achieve this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes) {
[node removeFromParent];
SKAction *pop = [SKAction playSoundFileNamed:#"pop.wav" waitForCompletion:NO];
[self runAction:pop];
}
}
Unfortunately, when there are several balloons in the bunch, this method can result in a single tap popping multiple balloons. This is because the sprite images overlap (even though the physics bodies do not). There is also the undesired effect that a tap on the string will have the same effect as a tap on the balloon.
I have access to the coordinates of the touch point, but is it even possible to detect whether a point lies within the area defined by the physics body (as opposed to the node)?
Use the physics world's bodyAtPoint: method:
SKPhysicsBody* body = [self.scene.physicsWorld bodyAtPoint:location];
bodyAtPoint is buggy but you have a working alternative.
You can create rays using baloon polygon path.
[self.physicsWorld enumerateBodiesAlongRayStart:rayStart end:rayEnd
usingBlock:^(SKPhysicsBody *body, CGPoint point,CGVector normal, BOOL *stop) {
if(body.categoryBitMask & baloonCategory){
SKPhysicsBody *contactBody=body;
CGPoint contactPoint=point;
*stop=YES;
}
}];
I looked but wasn't able to find a way of checking whether a touch is made within the physicsBody of a sprite. I would suggest separating the string and the ballon sprites.
You can try any the following:
Using separate sprite nodes for the balloon and the string and connecting them using a SKPhysicsJoint.
Subclass SKSpriteNode and add two sprites, i.e. the balloon and the string as children of the Sprite. Then u can check whether a touch made on the sprite is on the ballon or not.
Additionally for the multiple ballon pop problem, you can modify your code like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
//Instead of popping all nodes within the touch, pop only the first object.
if ([nodes count] > 0)
{
SKNode *node = [nodes firstObject];
[node removeFromParent];
SKAction *pop = [SKAction playSoundFileNamed:#"pop.wav" waitForCompletion:NO];
[self runAction:pop];
}
}
I have serious performance issues in my game. I'm developing a jigsaw puzzle game. I cut down an image into smaller images, create a UIView for each jigsaw piece and assign each image into it's own UIView's CALayer.
Then a I create random UIBezier paths for the shapes as masks and assign them into CAShapeLayers and then I assign the shape layers to my UIView.layer.mask properties.
It all works like a charm up to the point when I try to move the jigsaw pieces. I detect touches and move the appropriate pieces' center property (CGPoint).
But it is sooo slow and "laggy" when I move a piece over other pieces.
I googled a lot, tried calling setNeedsDisplayInRect: my container view etc.
Also I found, that these methods redraw the whole thing and I dont need to redraw, I need only to move the pieces. And I've found that animating is a good approach, since it uses methods built up on OpenGL. So I tried animating (moving) the pieces using the UIView class'method in my jigsaw piece object (subclass of UIView):
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.superview];
CGPoint offset = CGPointMake(touchLocation.x - _previousPoint.x, touchLocation.y - _previousPoint.y);
[UIView animateWithDuration:0
animations:^(void){
self.center = CGPointMake(self.center.x + offset.x, self.center.y + offset.y);
}
completion:^(BOOL finished){
}];
_previousPoint = touchLocation;
}
But it also didn't do the trick.
Does anyone have an idea how to improve the performance of this?
I still think that the "move only" approach would be the solution (not redrawing every frame, since redrawing is very expensive). But I don't know how to implement that.
Any ideas would be greatly appreciated, thanks in advance.
i am creating a project in which i have random Box2d bodies. Now i am drawing a line on basis of TouchesMoved by user in the DRAW method. i need to use the RayCasting method of Box2d to check for intersection between that line and the Box2D bodies.
i am using the following code for it in my Draw method
for(int i = 0; i < [pointTouches count]; i+=2)
{
CGPoint startPoint = CGPointFromString([pointTouches objectAtIndex:i]);
CGPoint endPoint = CGPointFromString([pointTouches objectAtIndex:i+1]);
ccDrawLine(startPoint, endPoint);
b2Vec2 start=[self toMeters:startPoint];
b2Vec2 end=[self toMeters:endPoint];
[self checkIntersectionbtw:start:end];
}
-(void)checkIntersectionbtw:(b2Vec2)point1:(b2Vec2)point2
{
RaysCastCallback callback;
world->RayCast(&callback, point1,point2);
if (callback.m_fixture)
{
NSLog(#"intersected");
checkPoint = true;
}
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint currentTouchArea = [myTouch locationInView:[myTouch view]];
CGPoint lastTouchArea = [myTouch previousLocationInView:[myTouch view]];
currentTouchArea = [[CCDirector sharedDirector] convertToGL:currentTouchArea];
lastTouchArea = [[CCDirector sharedDirector] convertToGL:lastTouchArea];
[pointTouches addObject:NSStringFromCGPoint(currentTouchArea)];
[pointTouches addObject:NSStringFromCGPoint(lastTouchArea)];
}
but the callback only tells the intersection when the line drawn completely passes the bodies. when user starts from some point outside and leaves the point inside the box2d body the callback doesn't say the line intersected. what am i possibly doing wrong??
Are you drawing a line or a curve? For a line, I assume that you only use the first point and the last point detected. For a curve, you use all the points detected to form the curve that you are drawing.
If you are drawing a curve then think I understand the problem. You are calculating the intersection line using the consecutive points detected by the touch system. These consecutive points are very close to each other which makes very small ray casts, and what might be happening is that you might be casting the line with a starting and ending point inside the balls, which might issue a negative collision.
If the objective is to detect if you are touching the balls, I suggest using a sensor maintained under the touch, and then checking a collision with this code in your update method:
for (b2ContactEdge* ce = sensorbody->GetContactList(); ce; ce = ce->next)
{
b2Contact* c = ce->contact;
if(c->IsTouching())
{
const b2Body* bodyA = c->GetFixtureA()->GetBody();
const b2Body* bodyB = c->GetFixtureB()->GetBody();
const b2Body* ballBody = (bodyA == sensorbody)?bodyB:bodyA;
...
}
}
If you really want to use a raycast, then I suggest saving a few consecutive points and make a vector with them, to avoid the small ray cast.
edit: Sorry, The example I wrote is in C++, but you should be able to find an equivalent for Objective-C.
Box2D's raycasts ignore any 'back' facing edges they hit, so if the ray starts inside a fixture, that fixture will be ignored. Simplest thing to do is cast the same ray in both directions.