i am currently writing a game with a number of rectangles (say 30), if a user clicks on one of the four sides a certain action will need to be taken. Trouble is each card will have the same side which will perform this action. For example with rectangle 1 the side which will perform this action will be the left, but rectangle 3 the side will be the top side. My guess is a pixel collision detection is needed here. What do you guys think? Also is there a good example on pixel collision using cocos2s out there?
You can simply use following code
if (CGRectIntersectsRect(Rect1, Rect2))
{
//Your code ...
}
USING above CGRectIntersectsRect you can detect the collision pixels within a rectangular area.
yes good point, the solution was a little messy but it worked, this is what i did: I subclassed CCSprite and created a new attribute called state saving the current position if rotated relative to that rotation. Depending on what side was touched i would use that information to determine which side of the rectangle was touched. –
if((spriteCentre1.x < spriteCentre2.x) && (xAxisDiff < yAxisDiff))
{
[HelloWorldLayer whichSideTouched:sprite1 sideTouched:kStateRightPlus touchingSprite:sprite2];
}
+(int)whichSideTouched:(SpriteCard *)sprite sideTouched:(int)touched touchingSprite:(SpriteCard *)sprite2
{
switch (sprite.state) {
case kStateUpPlus:
case kStateUpMinus:
if(touched == kStateDownPlus)
{
NSLog(# "touched up ");
[sprite setTop:sprite2];
retValue = kStateUpPlus;
}
else if(touched == kStateRightPlus)
{
NSLog(# "touch left");
[sprite setRight:sprite2];
retValue = kStateLeftPlus;
}
}
Thanks for that Dhaval, here is the code i wrote a future reference for anyone who wishes to do similar, it can be further fine tuned, if i figure out a more accurate way of doing this i will update this thread accordingly
-(void)touchWhichSide:(CCSprite *)sprite1 collidingSprite:(CCSprite *)sprite2
{
BOOL retValue = NO;
CGPoint spriteCentre1 = sprite1.position;
CGPoint spriteCentre2 = sprite2.position;
NSLog(#"X %f",spriteCentre2.x - spriteCentre1.x);
NSLog(#"Y %f",spriteCentre1.y - spriteCentre2.y);
float xAxisDiff = spriteCentre1.x - spriteCentre2.x;
float yAxisDiff = spriteCentre1.y - spriteCentre2.y;
NSLog(#"x axis %f",xAxisDiff);
NSLog(#"y axis %f",yAxisDiff);
if((spriteCentre1.x < spriteCentre2.x) && (xAxisDiff < yAxisDiff))
{
NSLog(#"right touch");
}
else if((spriteCentre2.x < spriteCentre1.x) && (xAxisDiff > yAxisDiff))
{
NSLog(#"left touch");
}
else if((spriteCentre2.y < spriteCentre1.y) && (yAxisDiff > xAxisDiff))
{
NSLog(#"Bottom touch");
}
else if((spriteCentre1.y < spriteCentre2.y) && (yAxisDiff < xAxisDiff))
{
NSLog(#"Top touch");
}
}
Related
I want to move my UIView of size (x=50,y=50) in the boundary of simulator screen means rectangular without animation infinitely.
To moving view continuously in your simulator boundary you have to put logic there is no predefined method without animation. if you are using animation then below given link is useful. How to repeat animation from current state not from startingstate? or without animation the below code will help you.
And yes please note that **
pos
** is a object of CGPoint class and you don't have to allocate it simply declare in interface.
- (void)viewDidLoad
{
pos = v1.center;
NSLog(#"POSITION === %f",pos.x);
[NSTimer scheduledTimerWithTimeInterval:0.05
target:self
selector:#selector(rotateBoundary)
userInfo:nil
repeats:YES];
[super viewDidLoad];
//[self performSelector:#selector(rotateBoundary) withObject:self afterDelay:5.0];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)rotateBoundary
{
if (pos.x>=20 && pos.x<=290 && pos.y==25)
{
NSLog(#"Top left to right.");
pos.x+=5;
v1.center = pos;
NSLog(#"pos.x === %f",pos.x);
}
if(pos.x >= 290 && pos.y<=430)
{
NSLog(#"Right top to down.");
pos.y+=5;
v1.center = pos;
NSLog(#"pos.y === %f",pos.y);
}
if(pos.y == 430 && pos.x>=20)
{
NSLog(#"Down right to left.");
pos.x-=5;
v1.center = pos;
NSLog(#"pos.x === %f",pos.x);
}
if (pos.x <= 20 && pos.y>=25)
{
NSLog(#"Down left to top.");
pos.y-=5;
v1.center = pos;
NSLog(#"pos.y === %f",pos.y);
}
}
I want a snow particle effect to follow my sprite and I tried some methods but all that ends up happening is the snow will just stay still instead of following. I did this one tutorial (will post as soon as I find it) thats shows how it do it with fire but didn't work out at all. Any tutorials or suggestions will be appreciated. I believe i have to add some kind of code to the snippet part where it says create enemy off screen.
[self schedule:#selector(gameLogicboss:) interval:180 ];
[self schedule:#selector(updateboss:)];
-(void)addTarget1 {
Boss *target1 = nil;
if ((arc4random() % 2) == 0) {{
target1 = [WeakAndFastBoss boss];
}} else {
target1 = [WeakAndFastBoss boss];
}
// Determine where to spawn the target along the Y axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minY = target1.contentSize.height/2;
int maxY = winSize.height - target1.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the target slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
target1.position = ccp(winSize.width + (target1.contentSize.width/2), actualY);
[self addChild:target1 ];
// Determine speed of the target
int minDuration = target1.minMoveDuration;
int maxDuration = target1.maxMoveDuration;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-target1.contentSize.width/2, actualY)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(spriteMoveFinished:)];
[target1 runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
target1.tag = 1;
[_targets addObject:target1];
}
-(void)gameLogicboss:(ccTime)dt {
[self addTarget1];
iterations_++;
}
- (void)updateboss:(ccTime)dt {
CGRect projectileRect = CGRectMake(projectile.position.x - (projectile.contentSize.width/2), projectile.position.y - (projectile.contentSize.height/2), projectile.contentSize.width, projectile.contentSize.height);
BOOL bossHit = FALSE;
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target1 in _targets) {
CGRect target1Rect = CGRectMake(target1.position.x - (target1.contentSize.width/2), target1.position.y - (target1.contentSize.height/2), target1.contentSize.width, target1.contentSize.height);
if (CGRectIntersectsRect(projectileRect, target1Rect)) {
//[targetsToDelete addObject:target];
bossHit = TRUE;
Boss *boss = (Boss *)target1;
boss.hp--;
if (boss.hp <= 0) {
_score ++;
[targetsToDelete addObject:target1];
}
break;
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
_projectilesDestroyed++;
if (_projectilesDestroyed > 2) {
}
}
if (bossHit) {
//[projectilesToDelete addObject:projectile];
[[SimpleAudioEngine sharedEngine] playEffect:#"explosion.caf"];
}
[targetsToDelete release];
}
-(void)spriteMoveFinishedboss:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:#"You Lose"];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
if (sprite.tag == 1) { // target
[_targets removeObject:sprite];
} else if (sprite.tag == 2) { // projectile
[_projectiles removeObject:sprite];
}
}
I Have found this, at CCParticleSystem.h
/** #typedef tCCPositionType
possible types of particle positions
/
typedef enum {
/* Living particles are attached to the world and are unaffected by emitter repositioning. */
kCCPositionTypeFree,
/** Living particles are attached to the world but will follow the emitter repositioning.
Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite.
*/
kCCPositionTypeRelative,
/** Living particles are attached to the emitter and are translated along with it. */
kCCPositionTypeGrouped,
you should set it like
myparticleSystem.positionType=kCCPositionTypeGrouped;
Hope it helps.
You don't need to update the particle emitter's position with the sprite.
You can add a particle system to the sprite as a child.
The particle system does need to be typed as such:
CCParticleSystem * booster = [CCParticleSystem particleWithFile:#"boosterParticles.plist"];
//customize your particles' options
//assuming you have a sprite defined as _motherShip
[_motherShip addChild:booster];
/*
* now that the particles are the _motherShip's child, you must remember
* to set the position relative to the mothership's origin...
*/
particles.position = ccp(15,0);
...So now whenever _motherShip.position changes, the booster will follow. It will even rotate with the ship.
Very simple logic without getting into code:
I spawn a sprite and give it a location (x, y).
For each sprite, I also spawn a CCParticleSystem, give it the required particle type, spawn rates etc.
The CCParticleSystem location is now set to be the same (x,y) location as the sprite, and it should get updated as the sprite's (x,y) location is update.
As the sprite and the CCParticleSystem move around, this location (x, y) is getting updates constantly at random in your schedule method per the interval step time.
Hope that makes sense.
I do this
vehicleParticleSystem = [CCParticleSystemQuad particleWithFile:#"vehicleParticle.plist"];
vehicleParticleSystem.position = ccp(_ship.position.x - _ship.contentSize.width/3, _ship.position.y - _ship.contentSize.height/3);
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
vehicleParticleSystem.scale = 0.5;
}
[self addChild:vehicleParticleSystem z:-1];
and update its position with this
- (void) updateParticleSystem:(ccTime)dt {
vehicleParticleSystem.position = ccp(_ship.position.x - _ship.contentSize.width/3, _ship.position.y - _ship.contentSize.height/3);
}
which is called in the -(void) update:(ccTime)dt method.
The ship is moved by the user via a joypad.
hope this helps. The positioning for the particle is slightly behind the vehicle for an engine effect.
Did you tried to update your particle position taking advantage of the update method?
I'm doing something like the following lines in one of my games and it works as I think you expect
-(void) update:(CCTime)delta{
_sprite.position = CGPointMake(newXPosition, newYPosition);
_fire.position = CGPointMake(_sprite.position.x, _sprite.position.y);
}
I hope it helps!
I have, for example, a UIButton that I placed in IB.
This UIButton has two functions depending on whether it is just touched up inside or dragged outside - it would be nice to at least keep it functioning for touch up inside.
I want to click on my button and 'drag outside' but use -touchesEnded over a rectangle when I finally release my click.
I know that one option is to ditch the UIButton and use -touchesBegan over a mask, but that is a lot more effort and requires a nice big rewrite (considering the 96 buttons).
So to rephrase slightly - I've clicked on a button and held down the mouse, while dragging the cursor (/finger) over to a different point in my view and I want my view to recognise a -touchesEnded when I finally let go. The problem is that the initial click is tied up in the button so -touchesEnded in my main view doesn't happen...
Am i trying to do this the wrong way? Also, am I being clear?
EDIT: #Heckman has phrased the question well below
If I understand your question correctly, you are touching one button, that is contained within some UIView, and want to be able to drag your finger out, and recognize the point in the buttons superview.
Sounds to me like you should detect the button press from the button, then make a call to the [UIButton superview], to tell the superview about the button pressing that started, and then handle the touch end within the view.
To notify the superview of the button that was pressed call something like (from your UIButton):
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.superview buttonPressed:self]
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self.superview touchesEnded:touches withEvent:event];
}
In your superview code (if you have a property buttonPressed):
-(void) buttonPressed:(UIButton *) button {
_buttonPressed = button;
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.buttonPressed) {
//Process the release from your drag here.
for(UITouch * touch in touches) {
//Use either of these to get the release position that you care about.
CGPoint releaseLocationInCurrentView = [touch locationInView:self];
CGPoint releaseLocationInButtonView = [touch locationInView:[self.buttonPressed]];
}
}
}
You might be able to use a UIPanGestureRecognizer on your UIView.
Here is some example code for how to implement gesture recognizers.
If you are looking for something like dragable items same as iphone homescreen icons then you can have a look to TTLauncherView sample from Three20 framework. http://three20.info/showcase/launcher
So, here's what I ended up doing, and it works quite nicely:
my UIButton on touchdragexit is assigned to an IBAction
-(IBAction)dragPoint:(id)sender {
//Do Something Useful in here - I assign the value to an Array that I can recall when I touch up inside one of 16 buttons
//Now pass the button touch on as a touch up outside
[myButton addTarget:self action:#selector(dragBegan:withEvent:) forControlEvents: UIControlEventTouchUpOutside];
}
so now I get my dragBegan like this:
- (void)dragBegan:(UIControl *)c withEvent:ev {
UITouch *touch = [[ev allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view]; // Get location of the moment I release the touch (touch up outside)
//now some long convoluted code to give me the location of a row of 16 buttons, of which I would like to know which one I touched up inside
UIButton *posButton;
int pos;
if(628.00<(touchPoint.y) && (touchPoint.y)<664.00){
if ((39.00<touchPoint.x && touchPoint.x<91.00) || (92.00<touchPoint.x && touchPoint.x<144.00) || (145.00<touchPoint.x && touchPoint.x<197.00) || (198.00<touchPoint.x && touchPoint.x<250.00)||(264.00<(touchPoint.x) && touchPoint.x<314.00)||(317.00<(touchPoint.x) && touchPoint.x<367.00)||(370.00<(touchPoint.x) && touchPoint.x<420.00)||(423.00<(touchPoint.x) && touchPoint.x<473.00)||(488.00<(touchPoint.x) && touchPoint.x<538.00) || (541.00<(touchPoint.x) && touchPoint.x<591.00) || (594.00<(touchPoint.x) && touchPoint.x<644.00) || (647.00<(touchPoint.x) && touchPoint.x<697.00)||(712.00<(touchPoint.x) && touchPoint.x<762.00)||(765.00<(touchPoint.x) && touchPoint.x<815.00)||(818.00<(touchPoint.x) && touchPoint.x<868.00)||(871.00<(touchPoint.x) && touchPoint.x<921.00)){
if(39.00<(touchPoint.x) && touchPoint.x<91.00){
posButton = SeqA;
pos=0;
}
else if(92.00<(touchPoint.x) && touchPoint.x<144.00){
posButton = SeqB;
pos=1;
}
else if(145.00<(touchPoint.x) && touchPoint.x<197.00){
posButton = SeqC;
pos=2;
}
else if(198.00<(touchPoint.x) && touchPoint.x<250.00){
posButton = SeqD;
pos=3;
}
else if(264.00<(touchPoint.x) && touchPoint.x<314.00){
posButton = SeqE;
pos=4;
}
else if(317.00<(touchPoint.x) && touchPoint.x<367.00){
posButton = SeqF;
pos=5;
}
else if(370.00<(touchPoint.x) && touchPoint.x<420.00){
posButton = SeqG;
pos=6;
}
else if(423.00<(touchPoint.x) && touchPoint.x<473.00){
posButton = SeqH;
pos=7;
}
else if(488.00<(touchPoint.x) && touchPoint.x<538.00){
posButton = SeqI;
pos=8;
}
else if(541.00<(touchPoint.x) && touchPoint.x<591.00){
posButton = SeqJ;
pos=9;
}
else if(594.00<(touchPoint.x) && touchPoint.x<644.00){
posButton = SeqK;
pos=10;
}
else if(647.00<(touchPoint.x) && touchPoint.x<697.00){
posButton = SeqL;
pos=11;
}
else if(712.00<(touchPoint.x) && touchPoint.x<762.00){
posButton = SeqM;
pos=12;
}
else if(765.00<(touchPoint.x) && touchPoint.x<815.00){
posButton = SeqN;
pos=13;
}
else if(818.00<(touchPoint.x) && touchPoint.x<868.00){
posButton = SeqO;
pos=14;
}
else if(871.00<(touchPoint.x) && touchPoint.x<921.00){
posButton = SeqP;
pos=15;
}
Now do something depending on the button you touched up inside
Other things I did - I created a mask of the original UIButton as a UIImageView that I made unhidden on a touchdragoutside event (and rebidden on the above touchupinside) so that I have a button I can drag
I want to create my own health indicator by aligning multiple images which represent one percent. So basically, based on the current health, I align as many one-percent parts as needed. However, removing them seems to be a problem.
-(void)updateHealthIndicator:(ccTime)delta{
//getting health and healthReduction (removed for better readability). This part does not affect the functioning of the loop...
if(health-healthReduction > 0 ){
NSLog(#"updatehealthindicator called ! health = %d ", health);
health -= healthReduction;
[self removeChildByTag:1000 cleanup:YES];
for (int i = health; i>0; i--){
onePercent = [CCSprite spriteWithFile:#"onepercentofhi.png"];
onePercent.anchorPoint = ccp(0,0);
onePercent.position = ccp(880+(-onePercent.contentSize.width) * i,712 );
[self addChild:onePercent z:2 tag:1000];
}
}
The health indicator shows up, but it only seems to remove the first "one-percent" piece. Are all sprites with tag 1000 affected by this [self removeChildByTag:1000 cleanup:YES]; ?
Only one view with the given tag is removed.
However, you could extend CCNode with the following code to remove all children
-(void) removeChildrenByTag:(int)aTag cleanup:(BOOL)cleanup
{
NSAssert( aTag != kCocosNodeTagInvalid, #"Invalid tag");
int w=[children count]-1;
while(w>=0){
CocosNode *node=[children objectAtIndex:w];
if( node.tag == aTag ){
[self detachChild:node cleanup:cleanup];
}
w--;
}
}
Note: This is a proposed solution to be integrated into Cocos2D but hasn't made it yet.
I know how to do shake for the iPhone has been asked a million times on here, but I can't seem to find anything useful regarding the accelerometer with Cocos2D. Everything i have found involves using views and I don't think i am using any views in Cocos2D, if I am they are hidden from me I think. I want to be able to tell when any sort of shake has occured within a CCLayer class?
I figured it out. In the layer class you need to put these lines;
self.isAccelerometerEnabled = YES;
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1/60];
shake_once = false;
Then implement this function in the layer class;
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
float THRESHOLD = 2;
if (acceleration.x > THRESHOLD || acceleration.x < -THRESHOLD ||
acceleration.y > THRESHOLD || acceleration.y < -THRESHOLD ||
acceleration.z > THRESHOLD || acceleration.z < -THRESHOLD) {
if (!shake_once) {
int derp = 22/7;
shake_once = true;
}
}
else {
shake_once = false;
}
}
shake_once is just a boolean to stop one shake from being registered more than once.