Cocos2d-x 3.0 game instance learning notes "card tower defense" Eighth --- monster appearance, monster tower defense
/* Description:
** 1. This game instance is the last game on the cocos2d-x game development journey, which is rewritten and noted down here with 3.0
** 2. I have also asked me about wood. He said: Write it as you like. First, do not copy the code completely. Second, You can note that it is a learning note-Good Guy.
** 3. Here With cocos2d-x 3.0 version rewriting, many places are different, but from the rewriting process also good learning cocos2d-x
*/
* ** All the code corresponding to each step and the resources used are packaged at the end.
* ** To avoid code overhead, the code in each step is marked. At first glance, the code is implemented in the first step to avoid errors and cannot be changed back (if not, Git should be used again ?)
* ** For the convenience of porting to the mobile phone, android testing is compiled for each step. Because the code can be compiled in win32 many times, compilation will fail, the code is tested.
Note content:
1. Simple Design Ideas
2. Code & Effects
3. Next note content
4. This Code & Resource download
I. Simple Design Ideas
1. Monsters need to be moved. It would be too complicated to put all the monsters in the Monster class. As a result, like the previous one, a mobile controller is also removed, and a Monster can walk along the route with a controller.
2. About the mobile controller, it is based on the previously edited monster route-that is, those ordered points to walk, then the mobile controller must use update to achieve automatic walking.
3. There is only one type of hero for the time being, but the monster has 5 and its attributes.
4. The number and type of monsters for each level are also configured through the plist file, but you only need to manually
Ii. Code & Effects
Here is a base class of the mobile controller:
# Define CHECK_MOVE_SPEED_LVL1 0.1f // moving interval # define CHECK_MOVE_SPEED_LVL2 0.04f # define interval 0.03f # define SPEED 1 class ControllerMoveBase: public Node {public: ControllerMoveBase ();~ ControllerMoveBase (); CC_SYNTHESIZE (int, _ speed, Speed); protected: Entity * _ entity; // Entity bool _ isMoving; // whether bool _ isXLeft is being moved; // shift bool _ isYUp to the left direction of x; // shift int _ checkMoveSpeed to the y direction; // move the interval // based on the current Pos and the target point, obtain the next coordinate Point getNextPos (Point curPos, Point destPos );};
Let's explain the getNextPos function. For example, if we have edited a map with two points (0, 0) (0,500), the first point of curPos is (0, 0) until it reaches the target point, which is always (0,500 ), after one second, it reaches (0,100). Then, curPos is the next point, and then calculates the next point based on the speed.
Implementation:
ControllerMoveBase: ControllerMoveBase () {_ isMoving = false; _ isXLeft = false; _ isYUp = false; _ speed = SPEED; _ checkMoveSpeed = success; _ entity = NULL;} ControllerMoveBase: :~ ControllerMoveBase () {CC_SAFE_RELEASE (_ entity);} Point ControllerMoveBase: getNextPos (Point curPos, Point destPos) {// move the direction if (curPos. x> destPos. x) {_ isXLeft = true;} else {_ isXLeft = false;} if (curPos. y <destPos. y) {_ isYUp = true;} else {_ isYUp = false;} // change the coordinate if (curPos. x <destPos. x & _ isXLeft = false) {curPos. x + = _ speed; if (curPos. x> destPos. x) {curPos. x = destPos. x ;}} else if (curPos. x> destPos. x & _ isXLeft) {curPos. x-= _ speed; if (curPos. x <destPos. x) {curPos. x = destPos. x ;}} if (curPos. y <destPos. y & _ isYUp = true) {curPos. y + = _ speed; if (curPos. y> destPos. y) {curPos. y = destPos. y ;}} else if (curPos. y> destPos. y & _ isYUp = false) {curPos. y-= _ speed; if (curPos. y <destPos. y) {curPos. y = destPos. y ;}} return curPos ;}
Then a simple mobile controller is used on monsters. H
Class ControllerSimpleMove: public ControllerMoveBase {public: ControllerSimpleMove ();~ ControllerSimpleMove (); static ControllerSimpleMove * create (Entity * entity); bool init (Entity * entity); void moveByPoslist (Vector <PosBase *> posList, int speed, int spanTime ); private: Vector <PosBase *> _ movePosList; // move PosBase * _ curDestPos Based on coordinate points; // float _ moveSpan; // move the interval float _ moveTimeCnt; // mobile timing // mobile updatevoid checkMoveUpdate (float delta); void nextMovePos ();};
. Cpp
ControllerSimpleMove: ControllerSimpleMove () {_ curDestPos = NULL; _ moveTimeCnt = 0; _ moveSpan = 0;} ControllerSimpleMove ::~ ControllerSimpleMove () {CC_SAFE_RELEASE (_ curDestPos);} ControllerSimpleMove * ControllerSimpleMove: create (Entity * entity) {ControllerSimpleMove * simpleMove = new ControllerSimpleMove (); if (simpleMove & simpleMove-> init (entity) {simpleMove-> autorelease () ;}else {CC_SAFE_DELETE (simpleMove);} return simpleMove;} bool ControllerSimpleMove :: init (Entity * entity) {CC_SAFE_RETAIN (entity); this-> _ entity = entity; thi S-> schedule (schedule_selector (ControllerSimpleMove: checkMoveUpdate); return true;} void ControllerSimpleMove: checkMoveUpdate (float delta) {if (_ isMoving) {_ moveTimeCnt + = delta * 1000; // The moving time reaches if (_ moveTimeCnt >=_ moveSpan) {_ moveTimeCnt = 0; // ** 8 ** move if (_ entity! = NULL) {Point entityPos = _ entity-> getPosition (); Point curDestPos = _ curDestPos-> getPos (); // Based on the moving speed, to obtain the next vertex location entityPos = getNextPos (entityPos, curDestPos); _ entity-> setPosition (entityPos); // when it reaches a vertex in the target PosBase List, update the target point if (entityPos. x = curDestPos. x & entityPos. y = curDestPos. y) {if (_ movePosList. size ()> 0) {nextMovePos () ;}}}} void ControllerSimpleMove: nextMovePos () {if (_ movePosList. size () <= 0) {return;} CC_SAFE_RELEASE (_ curDestPos); _ curDestPos = (PosBase *) _ movePosList. front (); CC_SAFE_RETAIN (_ curDestPos); _ movePosList. eraseObject (_ curDestPos);} void ControllerSimpleMove: moveByPoslist (Vector <PosBase *> posList, int speed, int spanTime) {this-> _ speed = speed; this-> _ moveSpan = spanTime; if (posList. size () <= 0) {return;} this-> _ movePosList. clear (); this-> _ movePosList = posList; this-> _ isMoving = true; nextMovePos ();}
In short, we can start with the public member function moveByPosList. Here we start to make _ isMoving true, and then start to move it step by step.
Contact real Monster
Enum category {enMonsterPropConf_ID, // monster category, // monster name enMonsterPropConf_Level, // monster level enMonsterPropConf_Type, // monster type category, // monster model category, // defensive force enMonsterPropConf_Hp, // blood volume enMonsterPropConf_Speed, // movement speed}; class Monster: public Entity {public: Monster ();~ Monster (); static Monster * createFromCsvByID (int monsterID); bool initFromCsvByID (int monsterID); // ** 8 ** has a moving method, call the mobile void moveByPosList (Vector <PosBase *> posList) in the monster manager; private: CC_SYNTHESIZE (int, _ level, Level); CC_SYNTHESIZE (float, _ showTime, showTime); ControllerSimpleMove * _ moveController ;};
There is also a public member function, moveByPosList, which is left in the monster manager to let the monster start the activity.
Monster: Monster () {_ moveController = NULL;} Monster ::~ Monster () {CC_SAFE_RELEASE (_ moveController);} Monster * Monster: createFromCsvByID (int monsterID) {Monster * monster = new Monster (); if (monster & monster-> initFromCsvByID (monsterID) {monster-> autorelease ();} else {CC_SAFE_DELETE (monster);} return monster;} bool Monster :: initFromCsvByID (int monsterID) {// ** 8 ** get IDconst char * chMonsterID = _ String: createWithFormat ("% d", monsterID)-> getCString (); // ** 8 ** bind the genie const char * monsterSprite = _ String: createWithFormat ("sprite/monster/monster_mongod.png", monsterID)-> getCString (); sprite * sprite = Sprite: create (monsterSprite); bindSprite (sprite); // ** 8 ** bind a mobile controller _ moveController = ControllerSimpleMove: create (this ); this-> addChild (_ moveController); // ** 8 ** attribute CsvUtil * csvUtil = CsvUtil: getInstance (); size csvSize = csvUtil-> getFileRowColNum ("csv/Monster.csv"); int line = csvUtil-> shard (chMonsterID, delimiter, "csv/Monster.csv"); setID (monsterID ); setLevel (csvUtil-> getInt (line, enMonsterPropConf_Level, "csv/Monster.csv"); setModeID (csvUtil-> getInt (line, delimiter, "csv/Monster.csv ")); setDefense (csvUtil-> getInt (line, delimiter, "csv/Monster.csv"); setHP (csvUtil-> getInt (line, enMonsterPropConf_Hp, "csv/Monster.csv ")); setSpeed (csvUtil-> getInt (line, enMonsterPropConf_Speed, "csv/Monster.csv"); return true;} void Monster: moveByPosList (Vector <PosBase *> posList) {if (posList. size () <= 0) return; _ moveController-> moveByPoslist (posList, 2, getSpeed ());
The attributes here are similar to those of heroes ....
You only need to pay attention to a few issues here. The csv/monster.csv should be slightly modified: the monster ID should be changed from top to bottom to 1 ~ 5, instead of 1000 ~ 1004, or directly use this resource to replace.
Then look at the monster manager, load the monster information through the plist file, and update the function to manage the appearance of the monster
Class MonsterManager: public Node {public: MonsterManager ();~ MonsterManager (); static MonsterManager * createWithLevel (int curLevel); bool initWithLevel (int curLevel); private: // ** 8 ** has multiple monsters, each of the displayed time increases progressively, and showTime is used to accumulate. float _ showTime is displayed one by one; // all coordinate points of ** 8 ** Vector <PosBase *> _ monsterPosList; // ** 8 ** the Monster did not appear. At first, all the monsters did not come out of the Vector <Monster *> _ notShowMonsterList; // all the Monster vectors in the ** 8 ** configuration file <Monster *> _ monsterList; // ** 8 ** In the init function, create a monster void createMonsters (int curLevel); // no number of monsters displayed int getNotShowMonsterCnt (); // the starting point of the monster PosBase * getMonsterStartPos (); PosBase * getMonsterEndPos (); // ** 8 ** displays the monster's update function void showMonster (float dt );};
----------------------------- Implementation:
MonsterManager: MonsterManager () {_ showTime = 0;} MonsterManager ::~ MonsterManager () {} MonsterManager * MonsterManager: createWithLevel (int curLevel) {MonsterManager * monsterMgr = new MonsterManager (); if (monsterMgr & monsterMgr-> initWithLevel (curLevel )) {monsterMgr-> autorelease ();} else {CC_SAFE_DELETE (monsterMgr);} return monsterMgr;} bool MonsterManager: initWithLevel (int curLevel) {// ** 8 ** create a monster createMonsters (curLevel) based on the level; // ** 8 ** enable update to enable this-> schedule (schedule _ Selector (MonsterManager: showMonster); return true;} void MonsterManager: createMonsters (int curLevel) {// ** 8 ** load route coordinate _ String * monsterPosPath = _ String: createWithFormat ("tollgate/monsterPos_level _ % d. plist ", curLevel); PosLoadUtil: getInstance ()-> loadPosWithFile (_ monsterPosList, enMonsterPos, monsterPosPath-> getCString (), this, 10, false ); // ** 8 ** read the monster configuration of the current level _ String * monsterConfPath = _ String: createWith Format ("tollgate/monster_level _ % d. plist ", curLevel); auto monsterConfList = FileUtils: getInstance ()-> getValueVectorFromFile (monsterConfPath-> getCString (); for (auto ref: monsterConfList) {auto temp_map = ref. asValueMap (); int id = temp_map.at ("id "). asInt (); float showTime = temp_map.at ("showTime "). asFloat (); if (id! = 0 & showTime! = 0.0f) {auto monster = Monster: createFromCsvByID (id); monster-> setShowTime (showTime); monster-> setVisible (false); _ monsterList. pushBack (monster); _ notShowMonsterList. pushBack (monster); this-> addChild (monster) ;}} int MonsterManager: getNotShowMonsterCnt () {return _ notShowMonsterList. size ();} PosBase * MonsterManager: getMonsterStartPos () {return _ monsterPosList. front ();} PosBase * MonsterManager: getMonsterEn DPos () {return _ monsterPosList. back ();} void MonsterManager: showMonster (float dt) {int notShowMonsterCnt = _ notShowMonsterList. size (); if (notShowMonsterCnt> 0) {_ showTime + = dt;} PosBase * monsterFirstPos = getMonsterStartPos (); // ** 8 ** stores the monsters that appear this time, then delete the file. In C ++, the file cannot be deleted during container traversal. A Vector <Monster *> temp_deletList; for (auto monster: _ notShowMonsterList) {if (monster! = NULL) {if (_ showTime> = monster-> getShowTime () {temp_deletList.pushBack (monster); monster-> setPosition (monsterFirstPos-> getPos ()); monster-> setVisible (true); monster-> moveByPosList (_ monsterPosList) ;}}for (auto deletMonster: temp_deletList) {_ notShowMonsterList. eraseObject (deletMonster );}}
Here, you can go to game/in the following resources to obtain the management configuration file for monsters.
---------------------------------------------
Add members to the MapLayer and add monster management to the init function.
//**8**_monsterMgr = MonsterManager::createWithLevel(_curLevel);this->addChild(_monsterMgr);
The following figure shows how to group monsters ......
Iii. Next content
Heroes do not do their duty and do not attack monsters !!!
IV:
----------------------------------
Resource & code
----------------------------------
Personal ignorance. Thank you for your correction and discussion.