Trigonometry for Game Programming: Part 2/2

Discussion of the official tutorials published on raywenderlich.com. Please only discuss the official tutorials here - for general questions, use the General Discussion forum instead.

Trigonometry for Game Programming: Part 2/2

This is the official thread to discuss the following blog post: Trigonometry for Game Programming: Part 2/2
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Ray Wenderlich
Blog: http://www.raywenderlich.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - -

rwenderlich

Posts: 2399
Joined: Thu Dec 23, 2010 4:14 pm
Has thanked: 28 times
Been thanked: 437 times

Re: Trigonometry for Game Programming: Part 2/2

Excellent work! Great tutorial! Not to brag, but I pretty much remember most of the Math I learned in High School!
Phoenix
Uber Haxx0r

Posts: 214
Joined: Wed Jun 29, 2011 7:20 pm
Has thanked: 7 times
Been thanked: 12 times

Re: Trigonometry for Game Programming: Part 2/2

Quick question although not 100% aligned with the topic of the tutorial, I have been playing around adding features like sneaky joystick instead of touch, etc to learn more about Cocos2D and trying to improve the game for it to be more fun.

I have been trying to add the capability to fire more than 1 shot at a time. To that effect I have created an array of 5 player missiles, and I check that array every time for collisions, etc. Everything compiles but keeps operating 1 shot at a time. I must have a flaw in the logic but I fail to detect where it is.

How do you normally implement a feature of keeping track of several shots at a time ? This is what I am doing:

Declaration:
Code: Select all
`CCSprite *_playerMissileSprite[4];`

in init:
Code: Select all
`for (int i =0; i<5; i++) {            _playerMissileSprite[i] = [CCSprite spriteWithFile:@"PlayerMissile.png"];            _playerMissileSprite[i].visible = NO;            [self addChild:_playerMissileSprite[i]];        }`

Checking for a hit:
Code: Select all
`for (int i=0; i<5; i++) {        if (_playerMissileSprite[i].visible)        {            float deltaX = _playerMissileSprite[i].position.x - _turretSprite.position.x;            float deltaY = _playerMissileSprite[i].position.y - _turretSprite.position.y;                        float distance = sqrtf(deltaX*deltaX + deltaY*deltaY);            if (distance < CannonHitRadius)            {                [[SimpleAudioEngine sharedEngine] playEffect:@"Hit.wav"];                                _cannonHP = MAX(0, _cannonHP - 10);                                _playerMissileSprite[i].visible = NO;                [_playerMissileSprite[i] stopAllActions];            }        }    }`

Firing using sneaky button:
Code: Select all
`if (attackButton.active == YES) {                for (int i=0; i<5; i++) {                        if (!_playerMissileSprite[i].visible) {                float angle = _playerAngle;                _playerMissileSprite[i].rotation = 90.0f - CC_RADIANS_TO_DEGREES(angle);                                _playerMissileSprite[i].position = _playerSprite.position;                _playerMissileSprite[i].visible = YES;                                float adjacent, opposite;                CGPoint destination;                                if (angle <= -M_PI_4 && angle > -3.0f * M_PI_4) {                    // Shoot down                    angle = M_PI_2 - angle;                    adjacent = _playerMissileSprite[i].position.y + Margin;                    opposite = tanf(angle) * adjacent;                    destination = ccp(_playerMissileSprite[i].position.x - opposite, -Margin);                }                else if (angle > M_PI_4 && angle <= 3.0f * M_PI_4) {                    // Shoot up                    angle = M_PI_2 - angle;                    adjacent = _winSize.height - _playerMissileSprite[i].position.y + Margin;                    opposite = tanf(angle) * adjacent;                    destination = ccp(_playerMissileSprite[i].position.x + opposite, _winSize.height + Margin);                }                else if (angle <= M_PI_4 && angle > -M_PI_4){                    // Shoot right                    adjacent = _winSize.width - _playerMissileSprite[i].position.x + Margin;                    opposite = tanf(angle) * adjacent;                    destination = ccp(_winSize.width + Margin, _playerMissileSprite[i].position.y + opposite);                }                else  // angle > 3.0f * M_PI_4 || angle <= -3.0f * M_PI_4                {                    // Shoot left                    adjacent = _playerMissileSprite[i].position.x + Margin;                    opposite = tanf(angle) * adjacent;                    destination = ccp(-Margin, _playerMissileSprite[i].position.y - opposite);                }                                                float hypotenuse = sqrtf(adjacent*adjacent + opposite*opposite);                ccTime duration = hypotenuse / PlayerMissileSpeed;                                id action = [CCSequence actions: [CCMoveTo actionWithDuration:duration position:destination],                             [CCCallBlock actionWithBlock:^                              {                                  _playerMissileSprite[i].visible = NO;                              }],                             nil];                                [_playerMissileSprite[i] runAction:action];                [[SimpleAudioEngine sharedEngine] playEffect:@"Shoot.wav"];                                            }                    } // for           }`
Will
Baby Hacker

Posts: 5
Joined: Wed Dec 14, 2011 2:13 pm
Has thanked: 0 time
Been thanked: 0 time

Re: Trigonometry for Game Programming: Part 2/2

Will wrote:I must have a flaw in the logic but I fail to detect where it is.

At first glance your code looks OK. What I would do it place some NSLog() statements here and there. For example, in the code that is supposed to first a new missile, print out the value of "i" for the missile that it fires.

Do the same thing in your update loop. This will tell you whether the sprites are really being used or not.
Like card games? Play my new game Mahjong Cards for iPad.

Hollance
Subscriber since Jan 26, 2014
iOS Tutorial Team Member

Posts: 5789
Joined: Wed Mar 09, 2011 8:33 pm
Location: The Netherlands
Has thanked: 0 time
Been thanked: 1002 times

Re: Trigonometry for Game Programming: Part 2/2

Thank you !

That helped. I had a flaw in the logic.

I was firing all 5 missiles simultaneously one on top of the other. That is why it seemed just 1. It went through the loop so fast it seemed only 1.

When I fired a missile I went through the loop checking missile visibility, so 1st time through all 5 were fired, and the same happened every time.

Need to figure a more clever way to check if missile has been fired or not. Thank you again for your great tutorial
Will
Baby Hacker

Posts: 5
Joined: Wed Dec 14, 2011 2:13 pm
Has thanked: 0 time
Been thanked: 0 time

Re: Trigonometry for Game Programming: Part 2/2

Brilliant tutorial thanks.

I have a question though as ive come into the tutorial mid way through. Im using a joystick which has degress from 0 to 360. Im picking up the joystick value at the point of the fire button being pressed as the angle variable, but it messes up the direction the projectile fires.

This is as far as ive got but something is seriously messed up!!

Code: Select all
`      if (angle <= 135 && angle > 45)        {            // Shoot up            angle = M_PI_2 - angle;            adjacent = self.contentSize.height - _Weapon.position.y + Margin;            opposite = tanf(angle) * adjacent;            destination = CGPointMake(_Weapon.position.x + opposite, self.contentSize.height + Margin);            //destination = CGPointMake(_Weapon.position.x + opposite, self.contentSize.height);                                            }        else if (angle > 135 && angle <= 225)        {            // Shoot left            adjacent = _Weapon.position.x + Margin;            opposite = tanf(angle) * adjacent;            destination = CGPointMake(-Margin, _Weapon.position.y - opposite);            //destination = CGPointMake(0,self.contentSize.height/2);                                            }        else if (angle > 225 &&  angle <= 315)        {            // Shoot down                        angle = M_PI_2 - angle;            adjacent = _Weapon.position.x + Margin;            opposite = tanf(angle) * adjacent;            destination = CGPointMake(_Weapon.position.x - opposite, -Margin);            //destination = CGPointMake(self.contentSize.width/2,0);                                }        else //right        {            adjacent = self.contentSize.width - _Weapon.position.x + Margin;            opposite = tanf(angle) * adjacent;            destination = CGPointMake(self.contentSize.width + Margin, _Weapon.position.y + opposite);            //destination = CGPointMake(self.contentSize.width,self.contentSize.height/2);                                            }`
TheRealms
n00b

Posts: 1
Joined: Sat Sep 13, 2014 6:43 pm
Has thanked: 0 time
Been thanked: 0 time

Great article. Had one question though. I'm a bit confused about the calculation of the destination of the missile. Particularly, the part where you stated:
"Be careful: now that the opposite side points the other way around, you need to subtract it rather than add it to the starting x-position."

Why does the opposite side have to be subtracted from the starting position? I thought "opposite" was just the length of the opposite side (which I'm assuming will always be positive). The destination of the missile is to the right of the original position, so my assumption would be that adding a positive value to the X value would move you in the right direction.
druland
n00b

Posts: 1
Joined: Sun Jun 14, 2015 9:49 pm
Has thanked: 0 time
Been thanked: 0 time