Question
I'm developing some poker software ~ purely for fun.
Now when it comes to the chips, I'm having a nightmare. One positioning them, two the denominations and THREE Selecting the ones I'll need! This seems almost impossible with my current design.
Basically, I draw an skshapenode give it the name of the denomination and the player name. However, this chip can be drawn 50 times with the same name.
When I come to animating these chips, I can only see a wall of impossibility..
once I've made a function to choose the right denominations of chips to use for a call or raise etc, how will I even begin to write this pseudo code?
I require 2 large chips, 1 small chip and 2 medium chips {
SKNode *node = [self childnodewithname:denomination, playername];
runaction..
}
Baring in mind, I'll only need to take 2 of the 20 that are there in the chip stack.. As well as change the ownership of the chip..
is this possible? or am I seriously overcomplicating the issue..?
You need to rework your solution a little bit. I would do something like this:
First, subclass a SKSpriteNode (or SK whatever node you like) to make a chip:
Chip.h
#interface Chip : SKSpriteNode
#property (nonatomic, retain) NSString *player;
#property int denomination;
#end
Chip.m
#implementation Chip
- (id)initWithColor:(UIColor *)color size:(CGSize)size
{
if(self = [super initWithColor:color size:size])
{
self.name = #"chip";
}
return self;
}
#end
Now you've got something you can reasonably enumerate and inspect.
Add a bunch of chips to your game scene:
GameScene.m
-(void)didMoveToView:(SKView *)view {
for(int i = 0; i < 50; i++)
{
Chip *chip = [[Chip alloc] initWithColor:[SKColor greenColor]
size:CGSizeMake(100.0, 100.0)];
chip.player = #"some player";
chip.denomination = 10;
[self addChild:chip];
}
}
Then when it's time to pop off a certain number of the chips:
-(void)popChipsFromPlayer:(NSString *)playerName
ofDenomination:(int)denomination
numberOfChips:(int)numChips
{
__block int i;
[self enumerateChildNodesWithName:#"chip"
usingBlock:^(SKNode *node, BOOL *stop) {
Chip *chip = (Chip *)node;
if(chip.denomination == denomination &&
[playerName isEqualToString:chip.player])
{
if(i==numChips)
return;
SKAction *moveUp = [SKAction moveByX:0.0
y:200.0
duration:3];
[chip runAction:moveUp];
i++;
}
}];
}
Call the method:
[self popChipsFromPlayer:#"some player"
ofDenomination:10
numberOfChips:3];
Related
I am building a Sprite Kit game where the player shoots a particle whenever the screen is pressed. How can I limit the touch inputs (let's say 2 recognized touch inputs per second) so that the player can't just quickly tap the screen to get unlimited shots?
Another solution:
Create a BOOL (I prefer to work with properties myself, so):
#property (nonatomic, assign) BOOL touchEnabled;
Set it to YES in the scene's init. Then it is fairly simple from thereon:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.touchEnabled){
self.touchEnabled = NO;
[self shootParticle];
[self performSelector:#selector(enableTouch) withObject:nil afterDelay:2.0];
}
...
- (void)shootParticle{
// whatever...
}
- (void)enableTouch{
self.touchEnabled = YES;
}
One of many possibilities:
#interface YourSceneName (){
int _amountBullets; //increase every time you shot and just shoot when _fireStop = NO
BOOL _fireStop; // init as NO at start
BOOL _needStartTime; // init as YES at start
CFTimeInterval _startTime;
}
#end
-(void)update:(CFTimeInterval)currentTime {
//set starttime
if(_needStartTime){
_startTime = currentTime;
_needStartTime = NO;
}
//timeinterval if 2 seconds, renew everything
if(currentTime - _startTime > 2){
_startTime = currentTime;
_amountBullets = 0
_fireStop = NO;
}
//set firestop to yes, method should be executed
if(_amountBullets = 2){
_fireStop = YES;
}
}
I am new in SpriteKit but this should work. I bet there are better possibilities. Also i havenĀ“t test the code. It shell show you the logic of how you could do it, hope I could help.
Here is a great Tutorial for working with time in SpriteKit.
I have the regular OpenGL / EAGL setup going on:
#interface EAGLView : UIView {
#public
EAGLContext* context;
}
#property (nonatomic, retain) EAGLContext* context;
#end
#implementation EAGLView
#synthesize context;
+ (Class)layerClass {
return [CAEAGLLayer class];
}
#end
#interface EAGLViewController : UIViewController {
#public
EAGLView* glView;
}
#property(nonatomic, retain) EAGLView* glView;
#end
#implementation EAGLViewController
#synthesize glView;
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
for (UITouch* touch in touches) {
CGPoint location = [touch locationInView:glView];
int index;
for (index = 0; index < gCONST_CURSOR_COUNT; ++index) {
if (sCursor[index] == NULL) {
sCursor[index] = touch;
break;
}
}
}
[super touchesBegan:touches withEvent:event];
}
That implementation includes corresponding touchesEnded/Canceled/Moved as well. The code fully works and tracks well.
I also make sure that I'm giving proper values for everything:
sViewController = [EAGLViewController alloc];
CGRect rect = [[UIScreen mainScreen] applicationFrame];
sViewController.glView = [[EAGLView alloc] initWithFrame:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)];
Assert(sViewController.glView);
sViewController.glView.userInteractionEnabled = YES;
sViewController.glView.multipleTouchEnabled = YES;
sViewController.glView.exclusiveTouch = YES;
It all compiles just fine, but I'm never receiving more than one UITouch. I don't mean in a single touchesBegan, but the index never goes past 0. I also set a breakpoint for the second time it enters that function, and putting two fingers on doesn't make it trigger.
If you want to detect multiple touches (and/or distinguish between a one finger, two finger etc. touch), try using a UIPanGestureRecognizer. When you set it up, you can specify the minimum and maximum number of touches. Then attach it to the view where you want to detect the touches. When you receive events from it, you can ask it how many touches it received and branch accordingly.
Here's the apple documentation:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIPanGestureRecognizer_Class/Reference/Reference.html
If you do this, you might not need to use the touchesBegan/Moved/Ended methods at all and, depending on how you set up the gesturerecognizer, touchesBegan/Moved/Ended may never get called.
Use [event allTouches] in place of touches. touches represents only the touches that have 'changed'. From the apple docs:
If you are interested in touches that have not changed since the last
phase or that are in a different phase than the touches in the
passed-in set, you can find those in the event object. Figure 3-2
depicts an event object that contains touch objects. To get all of
these touch objects, call the allTouches method on the event object.
It seems all I was missing was this:
sViewController.view = sViewController.glView;
I have about 10 draggable objects in my game that need to be removed entirely from the game at certain points, no use of these objects is required until a new game is started...
currently i say self.imageView = nil
However, the more images i discard this way, the slower the game becomes. I believe it is because the images are not completely gone and they are all being put at (0, 0) even though they are out of the view.
How else can i get rid of these image views in order to increase my performance?
Here is how I add the images to my view:
#interface GameView : UIView
{
UIImage *ball;
}
#property UIImageView *redBall;
-(id)initWithBallImage:(UIImageView *)ball;
#implementation GameView
-(id)initWithBallImage:(UIImageView *)ball
{
self = [super init]
if (self)
{
_redBall = ball;
return self;
}
return nil;
}
-(void)spawnBallWithColor:(BallColor)ballColor intoArray:(NSMutableArray *)array atPoint:(CGPoint)point
{
switch (ballColor) {
case kRedBall:
ball = [UIImage imageNamed:#"redBall.png"];
self.redBall = [[UIImageView alloc] initWithImage:ball];
self.redBall.center = point;
[array addObject:self.redBall];
[self addSubview:self.redBall];
break;
}
//I use the above method in an initWithLevel: method...
Then to remove the object from the view...
[self.redBall removeFromSuperview];
[self.redBall removeFromSuperview];
You also need
self.redBall = nil;
And you need to remove it from that array you added it to.
Additionally
self.redBall = [[UIImageView alloc] initWithImage:ball];
Is leaking memory if you aren't using automatic reference counting.
Firstly here is my .h files code where i declared everything...
#interface NextlLevel : UIViewController{
IBOutlet UIImageView *Coin1;
int score;
IBOutlet UILabel *scorelable;
}
#property (nonatomic, assign) int score;
#property (nonatomic, retain) IBOutlet UILabel *scorelable;
#end
I have also synthesised my implementations in my .m file here is the code...
#synthesize score;
#synthesize scorelable;
Secondly I have some code which just checks if my drag-able image has collided with a still image. Here is the code...
-(void) ifCollided {
if(CGRectIntersectsRect(Coin1.frame,MoneyBag.frame)){
Coin1.hidden = YES;
}
}
This code is just a basic way of checking for a collision but once the image has collided I want to add to a int which is displayed in a label.
The only way i thought i could do this was by ...
firstly adding this line of code to 'ifCollided'
[self scorecheck];
So now 'ifCollided' looks something like this:
-(void) ifCollided {
if(CGRectIntersectsRect(Coin1.frame,MoneyBag.frame)){
Coin1.hidden = YES;
[self scorecheck];
}
}
Thirdly I had to make 'scorecheck' I did this by...
-(void)scorecheck{
score++;
scorelable.text = [NSString stringWithFormat:#"%i", score];
}
}
Here is a image to show that the code I'm currently using is not working correctly. And therefore is not just adding just one to the int that i set to 0. I'm displaying the int in the score label (at the top of my screen). Due to the code not correctly working as long as you touch, drag and hold whilst colliding in the boundaries of the image with the collission rule (in this case the moneybag)
Here is to the image i was talking about:
Any help would be very appreciated
Edit:Here is what i was meant to do in the void ifCollided
-(void) ifCollided {
if (!Coin1.hidden)
{
Coin1.hidden = YES;
[self scorecheck];
}
}
Thanks #Elliott Perry
So, to clarify, you would like a mechanism that guarantees that the score will only increment once per each coin colliding with the moneybag?
There are any number of ways to do this but they all require you to keep track of which coins have already been processed in some way. You could give each of your coins a unique reference and store a collection of ids that represent coins that have already been processed, avoiding calling scorecheck if the collection contains the id of the coin in question.
Alternatively, and the method I'd go with, you can mark each coin to let yourself know not to process that coin a second time. Since your hiding the coins on collision, why not use the hidden property to determine whether to increment the score or not:
-(void)ifCollided
{
if(CGRectIntersectsRect(Coin1.frame,MoneyBag.frame))
{
if (!Coin1.hidden)
{
Coin1.hidden = YES;
[self scorecheck];
}
}
}
If for whatever reason that isn't feasible here is an example marking the coins using the tag property:
-(void)ifCollided
{
if(CGRectIntersectsRect(Coin1.frame,MoneyBag.frame))
{
if (Coin1.tag != 1)
{
Coin1.hidden = YES;
[self scorecheck];
Coin1.tag = 1;
}
}
}
I have found the following code and I need help with editing it. I am not really familiar with texture rendering.
First of all, init method takes a rect and magnifies only that area? How can I make it more dynamic and magnify only whatever is underneath the magnifying glass?
Secondly, Is it possible to change the shape to circle rather than rectangle?
Or Can I use an image as the frame of the magnifying glass?
Here is the code..
Cheers..
.h file
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Magnify : CCNode {
BOOL active;
CGRect rect;
CGFloat magnifyScale;
CCNode *renderNode;
CCRenderTexture *renderTexture;
}
- (id)initWithNodeToMagnify:(CCNode *)n rect:(CGRect)rectToMagnify scale:(CGFloat)scale;
- (void)enable;
- (void)disable;
.m file
#import "Magnify.h"
#implementation Magnify
- (id)initWithNodeToMagnify:(CCNode *)n rect:(CGRect)rectToMagnify scale:(CGFloat)scale
{
if (self = [super init]) {
self.visible = active = NO;
renderNode = n;
rect = rectToMagnify;
magnifyScale = scale;
renderTexture = [[CCRenderTexture renderTextureWithWidth:rect.size.width height:rect.size.height] retain];
[self addChild:renderTexture];
}
return self;
}
- (void)enable
{
self.visible = active = YES;
[self scheduleUpdate];
}
- (void)disable
{
self.visible = active = NO;
[self unscheduleUpdate];
}
- (void)drawAreaToTexture
{
[renderTexture beginWithClear:0.0 g:0.0 b:0.0 a:1.0];
// shift the renderNode's position to capture exactly the rect we need
CGPoint originalPosition = renderNode.position;
renderNode.position = ccpSub(originalPosition, rect.origin);
// scale the node as we want
CGFloat originalScale = renderNode.scale;
renderNode.scale = magnifyScale;
[renderNode visit];
// shift renderNode's position back
renderNode.position = originalPosition;
// scale back
renderNode.scale = originalScale;
[renderTexture end];
}
- (void)update:(ccTime)dt
{
[self drawAreaToTexture];
}
- (void)dealloc
{
[renderTexture release];
[super dealloc];
}
#end
OK, so, as I mentioned above for something like this, one possible answer is to use the CCLens3D class to get the "effect" of magnifying something in a circular manner.
I found using this to be a little tricky because it doesn't seem to work unless it's a child of the top level node of your 'scene'.
Here is some code I use to create a lens that moves around the screen, and then disappears:
// Create the lens object first.
//
CCLens3D *lens =
[CCLens3D actionWithPosition:fromPos
radius:50
grid:ccg(50, 50)
duration:2.0];
// Set the "size" of the lens effect to suit your needs.
//
[lens setLensEffect:1.0];
// In my case, I then move the lens to a new position. To apply an action on
// a lens, you need to give the actions to the actionManager in the
// CCDirector instance.
//
CCMoveTo *move = [CCMoveTo actionWithDuration:2.0 position:toPos];
// I had another action in this array, but this will do.
//
CCSequence *seq = [CCSequence actions:move, nil];
// Now tell the actionManager to move the lens. This is odd, but it works.
//
[[[CCDirector sharedDirector] actionManager] addAction:seq target:lens paused:NO];
// Now just for some more weirdness, to actually make the lens appear and operate
// you run it as an action on the node it would normally be a child of. In my case
// 'self' is the CCLayer object that is the root of the current scene.
//
// Note that the first action is the lens itself, and the second is a special
// one that stops the lens (which is a "grid" object).
//
[self runAction:[CCSequence actions:lens, [CCStopGrid action], nil]];
I imagine that you should be able to stop the grid by running the CCStopGrid action when you want to. In my case it is a programmed thing. In yours it might be when the user lets go of a button.