感谢您抽出宝贵时间来查看我的问题,因为我非常擅长编程,所以我们非常感谢任何帮助或指导方向。
...概述 我有一个我想要创建的简单游戏,它包括一个类“Ball'从屏幕左侧向右侧发射的精灵。这个" Ball"的速度精灵创建是随机的,每次都是" Ball"移动到屏幕右侧,一个点被添加到分数中。
问题.... 我遇到的问题是2" Balls"几乎在同一时间点火(随机发生一些时间)它们通过屏幕的右手不到一秒钟,当发生这种情况时,它似乎只增加1,当它应该加2得分(作为2球已通过右侧)。
下面是我的Ball启动器类的代码(使用此类随机调用球)。
如果您已经使用过或经历过Ray Wenderlichs'学习Cocos2D然后分配这个看起来很熟悉,因为在阅读完他的书之后我试图编辑他的代码来做我想要的事情(在阅读本书后,通过阅读本书的最佳学习方法,通过弄乱代码等)。 / p>
@implementation BL
@synthesize delegate;
@synthesize lauchingAnim;
@synthesize afterlauchingAnim;
-(void) dealloc {
delegate = nil;
[lauchingAnim release];
[afterlauchingAnim release];
[super dealloc];
}
//--The below shootPhaser method takes the current direction the launcher is facing and asks the delegate (gameplaylayer) to create the ball moving in that direction.
//--The below createPhaserWithDirection method was declared (created) in the GamePlayLayerDelegate protocol.
-(void)shootPhaser {
CGPoint phaserFiringPosition;
PhaserDirection phaserDir;
CGPoint position = [self position];
float xPosition = position.x + position.x * 0.51f;
float yPosition = position.y + position.y * 0.045f;
{
phaserDir = kDirectionRight;
}
phaserFiringPosition = ccp(xPosition, yPosition);
[delegate createPhaserWithDirection:phaserDir andPosition:phaserFiringPosition];
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
id action = nil;
characterState = newState;
switch (newState) {
case kStatespawning:
// CCLOG(@“launcher->Changing State to Spwaning");
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:@“lancher_1.png"]];
break;
case kStateIdle:
// CCLOG(@“laucher->Changing state to idle");
[self setDisplayFrame:
[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:@"lancher_1.png"]];
break;
case kStateFiring:
// CCLOG(@“launcher->Changing State to firing");
action = [CCSequence actions:
[CCAnimate actionWithAnimation:lauchingAnim],
[CCCallFunc actionWithTarget:self
selector:@selector(shootPhaser)],
[CCAnimate actionWithAnimation:afterlauchingAnim],
[CCDelayTime actionWithDuration:2.0f],
nil];
lauchingAnim.restoreOriginalFrame = NO;
afterlauchingAnim.restoreOriginalFrame = NO;
[self changeState:kStateIdle];
break;
case kStateDead:
CCLOG(@“launcher->changing state to dead");
break;
default:
CCLOG(@"unhandled state %d in launcher", newState);
break;
}
if (action !=nil) {
[self runAction:action];
}
}
-(void)updateStateWithDeltaTime: (ccTime)deltaTime andListOfGameObjects:(CCArray*)listOfGameObjects {
if (characterState == kStateFiring) {
// 5
if (characterState != kStateFiring) {
// If RadarDish is NOT already taking Damage
[self changeState:kStateFiring];
return;
}
}
if ((([self numberOfRunningActions] == 0) && (characterState != kStateDead)) ) {
// CCLOG(@"launcher Going to Idle!!!");
[self changeState:kStateIdle];
return;
}
}
-(void)initAnimations {
[self setLauchingAnim:[self loadPlistForAnimationWithName:@"lauchingAnim" andClassName:NSStringFromClass([self class])]];
[self setAfterlauchingAnim:[self loadPlistForAnimationWithName:@"afterlauchingAnim" andClassName:NSStringFromClass([self class])]];
}
-(id) initWithSpriteFrameName:(NSString*)frameName{
if ((self=[super init])) {
if ((self = [super initWithSpriteFrameName:frameName])) {
CCLOG(@"### Laauncher initialized");
[self initAnimations];
characterHealth = 3.0f;
gameObjectType = kBallLaucher;
// 3
[self changeState:kStateIdle];
}
}
return self;
}
@end
以下是我" Ball"的代码。类...
#import “Ball.h"
@implementation Ball
@synthesize delegate;
@synthesize myDirection;
@synthesize travelingAnim;
@synthesize ScoreAnim;
-(void) dealloc {
delegate = nil;
[travelingAnim release];
[ScoreAnim release];
[super dealloc];
}
-(void)changeState:(CharacterStates)newState {
[self stopAllActions];
[self setCharacterState:newState];
CGSize screenSize1 = [CCDirector sharedDirector].winSize;
CGPoint position = [self position];
CGPoint endPosition = ccp(screenSize1.width*1.5f, screenSize1.height*0.20f);
id action = nil;
//id action1 = nil;
switch (newState) {
case kStatespawning:
CCLOG(@“Spawning Ball");
[self setDisplayFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache]
spriteFrameByName:@"Ball_1.png"]];
break;
case kStateTravelling: {
movementAction = [CCMoveTo actionWithDuration:5.0f
position:endPosition];
}
break;
case kStateScore:
PLAYSOUNDEFFECT(SCORE);
CCLOG(@“Ball Past Left Of Screen => Add 1 to Score");
action = [CCSequence actions:
[CCCallFunc actionWithTarget:self selector:@selector(removeSelf)],
nil];
break;
default:
CCLOG(@“Ball -> Unknown CharState %d",
characterState);
break;
}
if (action !=nil)
[self runAction:action];
}
-(void)removeSelf{
CCLOG(@"Removing Ball Object Has Scored.");
[self setVisible:NO];
[self removeFromParentAndCleanup:YES];
return;
}
-(void)updateStateWithDeltaTime:(ccTime)deltaTime andListOfGameObjects:(CCArray *)listOfGameObjects {
CGPoint currentSpitePosition = [self position];
CGSize screenSize = [CCDirector sharedDirector].winSize;
if (currentSpitePosition.x > screenSize.width*1.1f) {{
[self changeState:kStateScore];
}
}
return;
}
if ([self numberOfRunningActions] == 0) {
if (characterState == kStatespawning) {
[self changeState:kStateTravelling];
return;
}
}
}
-(void)initAnimations {
[self setTravelingAnim:[self loadPlistForAnimationWithName:@"travelingAnim" andClassName:NSStringFromClass([self class])]];
[self setScoreAnim:[self loadPlistForAnimationWithName:@"ScoreAnim" andClassName:NSStringFromClass([self class])]];
}
-(id) initWithSpriteFrameName:(NSString*)frameName{
if ((self=[super init])) {
if ((self = [super initWithSpriteFrameName:frameName])) {
CCLOG(@"### Ball Initialised");
[self initAnimations];
characterHealth = 3.0f;
gameObjectType = kEnemyTypeBall;
[self changeState:kStatespawning];
}
}
return self;
}
@end
以下是我" GameplayLayer"的代码。类...
#import "GamePlayLayer.h"
#import “Ball.h"
#import “BL.h"
@implementation GamePlayLayer
@synthesize delegate;
-(void) dealloc {
delegate = nil;
[super dealloc];
}
-(void) update:(ccTime)deltaTime {
CCArray *listOfGameObjects =
[sceneSpriteBatchNode children];
for (GameCharacter *tempChar in listOfGameObjects) {
[tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:listOfGameObjects];
}
GameCharacter *tempChar = (GameCharacter*)[sceneSpriteBatchNode
getChildByTag:kEnemyTypeBall];
if ([tempChar characterState] == kStateScore) <==HERE I AM SEEING IF THE BALL HAS SCORED - THIS IS ALSO WHERE I THINK I MAY BE GOING WRONG SOMEHOW.
{
CCLOG(@"Add 1 Points To Score");
[self addPoint];
return;
}
}
-(void)addPoint
{
score = score + 1;
[scoreLabel setString:[NSString stringWithFormat:@"$%i", score]]; <===ADDING THE POINT TO THE SCORE
return;
}
-(void) createObjectOfType: (GameObjectType)objectType
withHealth:(int)initialHealth atLocation:(CGPoint)spawnLocation withZValue:(int)ZValue {
if (kBallLaucher == objectType) {
CCLOG(@"Creating launcher Object");
BL *ballLauncher = [[[BL alloc] init] initWithSpriteFrameName:@“launcher_1.png"];
[ballLauncher setCharacterHealth:initialHealth];
[ballLauncher setPosition:spawnLocation];
[sceneSpriteBatchNode addChild:tBT z:ZValue tag:kBallLaucher ];
[ballLauncher setDelegate:self];
[ballLauncher release];
}
}
**BELOW IS HOW I CONTROL WHEN THE BALL IS FIRED**
-(void)ChangeStateLaucher:(int)brandnewState withState:(CharacterStates)newState andObject:(GameObjectType)objectType; {
BL *bL = (BL*)
[sceneSpriteBatchNode getChildByTag:kBallLaucher];
int x = (arc4random() % 2);
if (x==0) {
CCLOG(@"Start Laucher Firing");
[bL changeState:kStateFiring];
count = 0;
}
if (x==1) {
CCLOG(@"No Laucher Firing");
count = count + 1;
if (count == 2) {
CCLOG(@"No Laucher Firing x2 - Start Laucher Firing");
[bL changeState:kStateFiring];
} else if (count > 3) {
CCLOG(@"No Laucher Firing x3 - Start Laucher Firing");
[bL changeState:kStateFiring];
}
}
[delegate ChangeStateLaucher:x withState:kStateFiring andObject:objectType];
}
-(void)createPhaserWithDirection:(PhaserDirection)phaserDirection andPosition:(CGPoint)spawnPosition {
CCLOG(@"Creating Ball from Gameplay Layer");
Ball *ballSprite = [[Ball alloc]initWithSpriteFrame:[[CCSpriteFrameCache
sharedSpriteFrameCache]
spriteFrameByName:@"Ball_1.png"]];
[ballSprite setPosition:spawnPosition];
[ballSprite setMyDirection:phaserDirection];
[ballSprite setCharacterState:kStatespawning];
[ballSprite setCharacterHealth:3.0f];
[sceneSpriteBatchNode addChild:ballSprite z:20 tag:kEnemyTypeBall];
[ballSprite release];
}
-(id)init {
self = [super init];
if (self !=nil) {
CGSize screenSize = [CCDirector sharedDirector]. winSize;
self.TouchEnabled = YES;
srandom(arc4random()); // Seeds the random number generator
[[CCSpriteFrameCache sharedSpriteFrameCache]
addSpriteFramesWithFile:@"scene1atlas.plist"]; // 1
sceneSpriteBatchNode =
[CCSpriteBatchNode batchNodeWithFile:@"scene1atlas.png"]; // 2
[self createObjectOfType:kBallLaucher withHealth:3 atLocation:ccp(screenSize.width * 0.05f, screenSize.height * 0.822f) withZValue:10];
[gameBeginLabel setPosition:ccp(screenSize.width/2,screenSize.height/2)]; // 2
[self addChild:gameBeginLabel]; // 3
id labelAction = [CCSpawn actions:
[CCFadeOut actionWithDuration:2.5f],
nil]; // 4
[gameBeginLabel runAction:labelAction];
lives = 3;
scoreLabel = [CCLabelBMFont labelWithString:@"$0"
fntFile:@“BallTest.fnt"];
scoreLabel.position = ccp(screenSize.width * 0.5f, screenSize.height * 0.9f);
[self addChild:scoreLabel
z:-1 tag:kNewScoreTagValue];
[self scheduleUpdate];
}
return self;
}
@end
我再次感谢任何花时间看这个问题的人,无论你是否发布了指针或答案。
感谢。
答案 0 :(得分:1)
我认为当屏幕上有多个Ball对象时,GamePlayLayer
update
方法无法接收其中一个球的状态变化,因为该球是一进入kStateScore
即被删除。
如果你在移除球之前添加一定的延迟,更新方法应该检测所有球的变化,你的问题应该得到解决。
在Ball.m
-(void)changeState:(CharacterStates)newState
函数中,修改状态kStateScore上的操作,如
action = [CCSequence actions:[CCDelayTime actionWithDuration:0.2],
[CCCallFunc actionWithTarget:self selector:@selector(removeSelf)],
nil];
尝试一下,让我知道这是否适合你!
修改强>
上述解决方案最终会增加多个点,因为球会因延迟而长时间保持在kStateScore状态。为了解决这个问题,我们可以引入一个新的状态调用kStateDead,并在添加点后将球状态更改为kStateDead。这将确保一个点只添加一次,我们也可以将球移除到kStateDead状态。新代码如下:
Ball.m
case kStateScore:
PLAYSOUNDEFFECT(SCORE);
CCLOG(@“Ball Past Left Of Screen => Add 1 to Score");
break;
case kStateDead:
action = [CCSequence actions:
[CCCallFunc actionWithTarget:self selector:@selector(removeSelf)],
nil];
default:
CCLOG(@“Ball -> Unknown CharState %d",
characterState);
break;
并在你的Gameplayer.m中
if ([tempChar characterState] == kStateScore) <==HERE I AM SEEING IF THE BALL HAS SCORED - THIS IS ALSO WHERE I THINK I MAY BE GOING WRONG SOMEHOW.
{
CCLOG(@"Add 1 Points To Score");
[self addPoint];
[tempChar changeState:kStateDead]; //change the state to dead after the point is added
return;
}