一、概要
我们组选择的审核代码来自ShineTeam,他们要完成的项目是一个与众不同的游戏。经过代码复审,他们的代码可以完成预设的功能,代码可读性好,较易于维护,有相当数量的注释来进行说明,代码分成了单独的模块进行处理,有单元测试来保证模块的可用性。
二、设计规范部分
项目模式设计是,有少量数字的存在,不便于阅读和维护,代码如下:
void AimLaser::setLaserOpacity(int value) { if(value < 0) value = 0; else if(value > 225) value = 225; m_laserModel->setOpacity(value); }
没有说明对value设置225的上限的原因。
其余绝大多数地方均无数字,或者用变量来进行说明,部分代码如下:
const float GRADESPEED[] = { 300, 350, 400, 600, 900, 1500 }; //各等级光束对应的速度
const int GRADEDAMAGE[] = {60, 100, 150, 250, 500, 1000}; //各等级光束对应的伤害
const char* GRADEFRAMENAME[] = { "Beam0000", "Beam0001", "Beam0002", "Beam0003", "Beam0004", "Beam0005" };
const float POINTINTERVAL = 2.0;
const float BEAMSPEEDRATES = 20;
由于他们选择了跨平台的设计,所以在移植方面没有问题。
在需要用到游戏引擎的部分,他们使用了cocos2d,并没有自己去写,在已经有可以调用的部分他们采用了调用而不是重新实现。
但在有的部分,例如重写一写方法时保留了原来的代码,将其注释掉而没有删除:
void AimLaser::reflectTrack() { ////创建BatchNode,批量渲染laser,更快一点。 //CCSpriteBatchNode* laserSegBatchNode = CCSpriteBatchNode::create("AimLaser.png"); //每次都要恢复激光最大的范围值。 float totalLaserLength= m_laserLength; Shield* hitShield = NULL; Shield* pre_hitShield = NULL; CCPoint laserBegin = m_tPosition; //碰撞时的激光的初始点 CCPoint laserEnd = laserBegin + totalLaserLength * ccpForAngle(CC_DEGREES_TO_RADIANS(-m_fRotation));//碰撞时激光的终点。 float leastLength = totalLaserLength; //记录碰撞点到上一个激光碰撞点的距离 CCPoint hitPoint = laserEnd; //记录上一个碰撞点 float newRotation = m_fRotation; //初始点,光束的方向AimLaser相同 while(totalLaserLength > 0) { CCArray* allShields = World::getCurrentWorld()->getShields(); Shield* shield; //检测碰撞,得到碰撞点最近的盾牌 CCARRAY_TFOREACH(allShields, shield, Shield*) { Segment* shieldSeg = (Segment*)shield->getBody(); Segment* laserSeg = new Segment(laserBegin, laserEnd); HitTestResult hitResult = hitTest(shieldSeg, laserSeg); if(hitResult.isCross()) { float hitLength = ccpDistance(hitResult.crossPoint, laserBegin); //找出离激光束最近的的碰撞点,并且该碰撞点所在盾牌不是上一次碰撞的盾牌(防止死循环) if(hitLength < leastLength && shield != pre_hitShield) { leastLength = hitLength; hitPoint = hitResult.crossPoint; hitShield = shield; } } } //totalLaserLength保存的是激光被拦截之后的长度 if(totalLaserLength < leastLength) totalLaserLength = 0; else totalLaserLength -= leastLength; //计算出的被拦截的长度,用激光条束(laser)填满它 while(leastLength > 0) { CCSprite* laser = CCSprite::createWithSpriteFrameName("AimLaser0000"); float laserLength = laser->getContentSize().width; laser->setAnchorPoint(CCPointMake(0, 0.5)); laser->setPosition(laserBegin); laser->setRotation(newRotation); int opacity = (int)(225 * (totalLaserLength + leastLength) / m_laserLength); laser->setOpacity(opacity); m_laserBatchNode->addChild(laser); //每填一个条束,应该填的长度减少相应的长度,直到剩余未填长度(leastLength)为0 if(leastLength < laserLength) { laser->setTextureRect(CCRectMake(0,0, leastLength, laser->getContentSize().height)); //laser->setContentSize(CCSizeMake()); leastLength = 0; } else leastLength -= laserLength; //getParent()->addChild(laser); m_laserSeg->addObject(laser); laserBegin = laserBegin + laserLength * ccpForAngle(CC_DEGREES_TO_RADIANS(-newRotation));//碰撞时激光的终点。 } //如果碰撞发生了,更新碰撞检测的状态,并且保存本次碰撞所在的盾牌,以防止下次遍历陷入死循环 if(hitShield) { pre_hitShield = hitShield; newRotation = 2 * hitShield->getRotation() - newRotation; //newRotation表示的是上一个碰撞后得到的激光角度。这里更新它。 laserBegin = hitPoint; laserEnd = laserBegin + totalLaserLength * ccpForAngle(CC_DEGREES_TO_RADIANS(-newRotation));//碰撞时激光线段的终点。 leastLength = totalLaserLength; } } } //void AimLaser::reflectTrack() //{ // //每次都要恢复激光最大的范围值。 // float totalLaserLength= m_laserLength; // // Shield* hitShield = NULL; // Shield* pre_hitShield = NULL; // // CCPoint laserBegin = m_tPosition; //碰撞时的激光的初始点 // CCPoint laserEnd = laserBegin + totalLaserLength * ccpForAngle(CC_DEGREES_TO_RADIANS(-m_fRotation));//碰撞时激光的终点。 // float leastLength = totalLaserLength; //记录碰撞点到上一个激光碰撞点的距离 // CCPoint* hitPoint = new CCPoint(laserEnd); //记录上一个碰撞点 // float newRotation = m_fRotation; //初始点,光束的方向AimLaser相同 // // while(totalLaserLength > 0) // { // CCArray* allShields = World::getCurrentWorld()->getShields(); // Shield* shield; // // //检测碰撞,得到碰撞点最近的盾牌 // CCARRAY_TFOREACH(allShields, shield, Shield*) // { // Segment* shieldSeg = (Segment*)shield->getBody(); // Segment* laserSeg = new Segment(laserBegin, laserEnd); // HitTestResult hitResult = hitTest(shieldSeg, laserSeg); // if(hitResult.isCross()) // { // float hitLength = ccpDistance(hitResult.crossPoint, laserBegin); // // //找出离激光束最近的的碰撞点,并且该碰撞点所在盾牌不是上一次碰撞的盾牌(防止死循环) // if(hitLength < leastLength && shield != pre_hitShield) // { // leastLength = hitLength; // hitPoint = new CCPoint(hitResult.crossPoint); // hitShield = shield; // } // } // } // // //计算出hitPoint.如果没有发生碰撞,hitPoint保持初始值laserEnd不变(即800 激光尾端)。 // m_hitPointArray->addObject(hitPoint); // // //totalLaserLength保存的是激光被拦截之后的长度 // if(totalLaserLength < leastLength) // totalLaserLength = 0; // else // totalLaserLength -= leastLength; // // //如果碰撞发生了,更新碰撞检测的状态,并且保存本次碰撞所在的盾牌,以防止下次遍历陷入死循环 // if(hitShield) // { // pre_hitShield = hitShield; // newRotation = 2 * hitShield->getRotation() - newRotation; //newRotation表示的是上一个碰撞后得到的激光角度。这里更新它。 // laserBegin = *hitPoint; // laserEnd = laserBegin + totalLaserLength * ccpForAngle(CC_DEGREES_TO_RADIANS(-newRotation));//碰撞时激光线段的终点。 // leastLength = totalLaserLength; // } // } //}
多余代码可以清除掉。
三、代码规范部分
代码缩进符合要求,行宽合适,括号逻辑表达清楚,在仅有一行语句的情况依然用大括号进行分隔:
FarSpace::~FarSpace() { World::getCurrentWorld()->unregEventHandler(this); CCArray* children = this->getChildren(); CCObject* _obj; CCARRAY_FOREACH(children, _obj) { CC_SAFE_RELEASE(_obj); } }
也有一行语句却没有括号的情况:
if(totalLaserLength < leastLength) totalLaserLength = 0; else totalLaserLength -= leastLength;
命名十分规范,正确使用下划线,在需要的地方使用大写来命名。
对数据进行了封装,使用方法来对私有属性进行修改/读取。
int EnemyCraft::getMoney() { return m_money; } void EnemyCraft::setMoney(int value) { if(value >= 0) m_money = value; }
有一定数量的注释,但有些程序段的注释有些缺乏,
void Beam::update(float dt) { // update body area // 将上一个位置点记为起点,当前位置点记为终点 CCAssert(getParent(), "Beam::update - not added to any layer"); CCPoint newEnd = getBeamStripPosition(); Segment* seg = (Segment*)m_body; seg->begin = seg->end; seg->end = newEnd; strikeTarget(); }
bool FarSpace::shipSpeedChanged(float scale) { Dust* dust; CCArray* dustArray = Dust::getDustArray(); CCARRAY_TFOREACH(dustArray, dust, Dust*) { dust->stopAllActions(); float speedReal = dust->getSpeed() * scale; dust->setSpeed(speedReal); CCPoint position = dust->getPosition(); CCFiniteTimeAction* moveTo = CCMoveTo::create((position.y + 50) / speedReal, ccp(position.x, -50)); CCCallFunc* remove = CCCallFunc::create(dust,callfunc_selector(Dust::remove)); dust->runAction(CCSequence::create(moveTo, remove, NULL)); } return false; }
有的地方仅一行注释或者完全没有,给阅读带来一定的困难。
四、具体代码部分
大多数地方没有错误处理,有的if并没有else来对其余情况进行处理,switch语句中的default语句采用了return 0或者break,也有未处理的情况。
void EnemyCraft::setBodyRadius(float value) { if(value > 0) { m_bodyRadius = value; if(m_body && m_body->type == BTYPE_ROUND) { Round* round = (Round*)m_body; round->radius = m_bodyRadius; } } }
Bullet* EnemyCraft::createBullet() { if(!isDistanceSafe()) return NULL; Bullet* bRet = NULL; switch(m_bulletType) { case BT_BEAM_1: bRet = Beam::create(1); break; case BT_BEAM_2: bRet = Beam::create(2); break; case BT_BEAM_3: bRet = Beam::create(3); break; case BT_BEAM_4: bRet = Beam::create(4); break; case BT_BEAM_5: bRet = Beam::create(5); break; case BT_BEAM_6: bRet = Beam::create(6); break; case BT_BOMB: bRet = Bomb::create(); break; //case BT_CANON: // bRet = Cannon::create(); // break; case BT_MISSILE: bRet = Missile::create(); break; } if(bRet) { bRet->setSide(SIDE_ENEMY); bRet->addToWorld(getPosition(), getAbsoluteShootDirection() + CCRANDOM_MINUS1_1() * m_shootScatter); } return bRet; }
还有的地方使用了do{}while(0)的写法,但没有break。据解释,do{}while(0)是为了返回初始化失败的情况,而有的人在写的时候却没有加上break的部分。
bool Dust::init() { bool bRet = false; do { ResourceManager* rm = ResourceManager::getSingleton(); float scale = 1.0f + CCRANDOM_0_1(); // add visual - the mother point of the dust m_Dust = CCSprite::create(rm->getImageRes("Star")); m_Dust->setScale(scale); //m_Dust->retain(); addChild(m_Dust); // add visual - tail of the dust m_Tail = createParticleSystem(rm->getParticle("DustTail")); m_Tail->setPositionType(kCCPositionTypeRelative); m_Tail->setSpeed(100); //m_Tail->retain(); addChild(m_Tail); m_Speed = DUSTSPEED; scheduleUpdate(); //World::getCurrentWorld()->regEventHandler(this); bRet = true; } while (0); return bRet; }
应该有