Create a tile-Based Map game with cocos2d-x: Join enemies and battle (3)

Source: Internet
Author: User

This tutorial is based on the Child Dragon Mountain Man translation cocos2d iPhone tutorial, rewrite with cocos2d-x for xNa engine, plus some of my processing and production. In the tutorial, most of the text images are from the original author and the author of the translation, Long Shan, and many others are my own understandings and processing. I would like to thank the original author for his tutorial and the translation of Zilong shangren. This tutorial is only for learning and communication purposes. Do not conduct commercial communications.
IPhone tutorial address: http://www.cnblogs.com/andyque/archive/2011/05/07/2039481.html
IPhone tutorial original address: http://geekanddad.wordpress.com/2010/06/22/enemies-and-combat-how-to-make-a-tile-based-game-with-cocos2d-part-3/

Program:

This tutorial is a follow-up to the series of "Create a tile map-based game with cocos2d-x. If you have not read the previous two tutorials, you can find the other two tutorials on my blog.
In the second part of the tutorial, Ray teaches you how to create a collision-able area in a map and how to use the tile attribute, how to create items that can be picked up, how to dynamically modify maps, and how to use "heads up display" to display scores.
In this tutorial, we will join the enemy. In this way, your ninja can throw darts at them and increase the game logic of victory and failure. But first, you have to download some related resource files.

In this tutorial, we will join the enemy. In this way, your ninja can throw darts at them and increase the game logic of victory and failure. But first, you have to download some related resource files. This zip file contains the following content: 1. An enemy genie 2. A Ninja dart 3. Two buttons for use later in the tutorial.

.
Add enemies
By the end of the second tutorial, the game was already cool, but it was not a complete game. Your ninja can easily wander around and eat as you like. However, when will a player win or fail. Imagine that two enemies are chasing your ninja, and this game will be even more interesting.
Position of the enemy
Now, go back to the tiled software and open your tilemap (tilemap. tmx ).
Add an object to the Object layer. It can be near the player, but it should not be too close. Otherwise, when the enemy shows up, the game will be over. This location will become the position where the enemy appears and name it "enemyspawn1 ".
Objects in an object group (all objects in the object Layer constitute an object group) are stored in a list <dictionary> and the object name is used as the value. This means that each location point must have a unique name. Although we can traverse all the dictionary to see if any value starts with "enemyspawn", this is very inefficient. Instead, we use an attribute to indicate that each given object represents the position of an enemy.


Assign an attribute "enemy" to this object and a value of 1. if you want to expand based on this tutorial and add other types of enemies, you can use these enemy attribute values to represent different types of enemies.
Now, make 6-10 such enemies with location point objects, and their distance from the player is also somewhat different. Define an "enemy" attribute for each object and assign it to 1. Save the map and update it to the project.
  
  
Start creating enemies
Now we will display the enemy to the map. First, add the following method to the tilemaplayer class:

        void addEnemyAtXY(int x, int y)        {            CCSprite enemy = CCSprite.spriteWithFile("images/enemy1");            enemy.position = new CCPoint(x, y);            this.addChild(enemy);        }

Add the following after the if statement for adding player in init:

                    if (item.ContainsValue("EnemySpawn1"))                    {                        int ex =  Convert.ToInt32(item["x"]);                        int ey = Convert.ToInt32(item["y"]);                        this.addEnemyAtXY(ex, ey);                    }

Cyclically traverse the Object List to determine whether it is an enemy object. If yes, obtain its X and Y coordinate values, and then call the addenemyatxy method to add them to the appropriate place.
This addenemyatxy method is straightforward. It only creates an enemy genie at the input x and y coordinate values.
If you compile and run it, you will see these enemies appear in the positions you set in the tiled tool before. It's cool!

However, there is a problem here: these enemies are dummies and they will not kill your ninja.
Move them
So now we will add some code so that these enemies will chase our player to run. Because player will certainly move, and we must dynamically change the movement direction of the enemy. To achieve this goal, we let the enemy move 10 pixels each time, and then adjust their direction before the next movement. Add the following code to the tilemaplayer class:

        /// <summary>        /// callback, starts another iteration of enemy movement        /// </summary>        /// <param name="sender"></param>        void enemyMoveFinished(object sender)        {            CCSprite enemy = sender as CCSprite;            this.animateEnemy(enemy);        }        /// <summary>        /// a method to move enemy 10 pixls toward the player        /// </summary>        /// <param name="enemy"></param>        void animateEnemy(CCSprite enemy)        {             //speed of the enemy            float acturalDuration = 0.3f;            var actionMove = CCMoveBy.actionWithDuration(acturalDuration, CCPointExtension.ccpMult(                CCPointExtension.ccpNormalize(                CCPointExtension.ccpSub(player.position, enemy.position)), 10));            var actionMoveDone = CCCallFuncN.actionWithTarget(this, enemyMoveFinished);            enemy.runAction(CCSequence.actions(actionMove, actionMoveDone));        }

Add the following at the end of the addenemyatxy method:

this.animateEnemy(enemy);

Animateenemy: The method creates two actions. The first action moves 10 pixels toward the enemy. The time is 0.3 seconds. You can change the time to make it move faster or slower. The second action will call the enemymovefinished: method. We use ccsequence actions to combine them, so that when the enemy stops moving, they can immediately execute enemymovefinished: The method can be called. In the addenemyatx: Y: method, we call the animateenemy: Method to move the enemy towards the player. (Actually, this is a recursive call. Every time we move 10 pixels, we call the enemymovefinished method)

Very concise! However, if the enemy faces the player each time he moves, isn't it more realistic? You only need to add the following statement to the animateenemy method:

            //immediately before creating the actions in animateEnemy            //rotate to face the player             CCPoint diff = CCPointExtension.ccpSub(player.position, enemy.position);            double angleRadians = Math.Atan((double)(diff.y / diff.x));            float angleDegrees = MathHelper.ToDegrees((float)angleRadians);            float cocosAngle = -1 * angleDegrees;            if (diff.x < 0)            {                cocosAngle += 180;            }            enemy.rotation = cocosAngle;

This Code calculates the angle of each player relative to the enemy, and then rotates the enemy to face the player.

The full screen monsters seem to be a little too many ..

Ninja darts
It's pretty good, but the player is a ninja! He should be able to protect himself!
We will add a mode (modes) to the game ). Mode is not the best way to implement this function, but it is simpler than other methods, and this method can also run in the simulator (because there is no need to touch more ). Because of these advantages, we use this method in this tutorial. First, the UI will be created. In this way, players can easily switch between the "Mobile mode" and "throwing darts" modes. We will add a button to use this function for conversion. (From the Mobile mode to the darts mode ).
Now, we will add some attributes for better communication between the two layers. Add the following code to the tilemaphud class:

        int _mode = 0;        public int mode {             get {                return _mode;            }         }        /// <summary>        /// callback for the button        /// mode 0 = moving mode        /// mode 1 = ninja star throwing mode        /// </summary>        /// <param name="sender"></param>        void projectileButtonTapped(object sender)        {            if (_mode == 1)            {                _mode = 0;            }            else                _mode = 1;        }    //in the init method         CCMenuItem on = CCMenuItemImage.itemFromNormalImage(@"images/projectile-button-on", @"images/projectile-button-on");            CCMenuItem off = CCMenuItemImage.itemFromNormalImage(@"images/projectile-button-off", @"images/projectile-button-off");            CCMenuItemToggle toggleItem = CCMenuItemToggle.itemWithTarget(this, projectileButtonTapped, on, off);            CCMenu toggleMenu = CCMenu.menuWithItems(toggleItem);            toggleMenu.position = new CCPoint(100, 32);            this.addChild(toggleMenu);

What did we do above? We added a variable mode for judgment. Add another button.

Compile and run. A button appears in the lower left corner, and you can open or close it. But this does not have any impact on the game. Our next step is to increase the launch of darts.

Launch darts
Next, we will add some code to check which mode the player is currently in, and different events are affected when the user clicks the screen. If the player is in the mobile mode, move the player. If the player is in the shooting mode, throw the darts. Add the following code in the cctouchended method:

if (hud.mode ==0) {// old contents of ccTouchEnded:withEvent:} else {// code to throw ninja stars will go here}

In this way, players can only move in the mobile mode. The next step is to add code to enable ninja to launch darts. Add some cleanup code in the tilemaplayer class before adding else:

        void projectileMoveFinished(object sender)        {            CCSprite sprite = sender as CCSprite;            this.removeChild(sprite, true);        }

Okay. Have you seen the comments in the above else section:
// Code to throw ninja stars will go here
Add the following code after the above annotation:

//code to throw ninja stars will go here                //Find where the touch is                 CCPoint touchLocation = touch.locationInView(touch.view());                touchLocation = CCDirector.sharedDirector().convertToGL(touchLocation);                touchLocation = this.convertToNodeSpace(touchLocation);                //Create a projectile and put it at the player's location                CCSprite projectile = CCSprite.spriteWithFile(@"images/Projectile");                projectile.position = new CCPoint(player.position.x, player.position.y);                this.addChild(projectile);                //Determine where we wish to shoot the projectile to                float realX;                //Are we shooting to left or right?                CCPoint diff = CCPointExtension.ccpSub(touchLocation, player.position);                if (diff.x > 0)                {                    realX = tileMap.MapSize.width * tileMap.TileSize.width + projectile.contentSize.width / 2;                }                else                    realX = -tileMap.MapSize.width * tileMap.TileSize.width - projectile.contentSize.width / 2;                float ratio = diff.y / diff.x;                float realY = (realX - projectile.position.x) * ratio + projectile.position.y;                CCPoint realDest = new CCPoint(realX, realY);                //Determine the length of how far we're shooting                float offRealX = realX - projectile.position.x;                float offRealY = realY - projectile.position.y;                double length = Math.Sqrt((double)(offRealX * offRealX + offRealY * offRealY));                float velocity = 480 / 1;//480pixls/1sec                float realMoveDuration = (float)length / velocity;                //Move projectile to actual endpoint                var actionMoveDone = CCCallFuncN.actionWithTarget(this, projectileMoveFinished);                projectile.runAction(CCSequence.actions(CCMoveTo.actionWithDuration(realMoveDuration,realDest),actionMoveDone));

This code will launch a dart in the direction of the user's click on the screen. For the complete details of this piece of code, you can look at my other article "using a cocos2d-x to make a simple Windows Phone 7 game (a)". Of course, the comments after the original author's article will be clearer.

Projectilemovefinished: The method will be removed when the darts move out of the screen. This method is critical. Once we start collision detection, we will traverse all the darts cyclically. If we do not remove a dart from the fly out of the screen range, the list of storage darts will grow and the game will become slower and slower. Compile and run the project. Now, your ninja can throw a dart to the enemy.


Collision Detection
The next step is to destroy the enemy when the darts hit the enemy.
So what should we do. I would like to use box2d for collision detection, but the conventional collision detection is also possible. This provides two solutions.
First, add a class to the classes folder. Name it gameoverscene and inherit it from ccscene.
Modify the Code as follows;

       public GameOverScene(bool isWin)        {            string winMsg;            if (isWin)            {                winMsg = "YOU WIN!";            }            else                winMsg = "YOU LOSE!";            CCLabelTTF label = CCLabelTTF.labelWithString(winMsg, "Arial", 32);            label.position = new CCPoint(400, 300);            this.addChild(label);            this.runAction(CCSequence.actions(CCDelayTime.actionWithDuration(3.0f), CCCallFunc.actionWithTarget(this, gameOverDone)));        }        void gameOverDone()        {            TileMapScene pScene = new TileMapScene();            CCDirector.sharedDirector().replaceScene(pScene);        }    }

In this way, gameoverscene is completed. The above code is clear. Is to add a label and jump to the game interface after 3 seconds of delay.

Part1: box2d Detection
This part, we use box2d for collision detection, if you do not understand box2d, you can see my blog inside the <cocos2d-x for WP7> In the cocos2d-x using box2d and <cocos2d-x
For WP7> Use box2d for collision detection (and only for collision detection ).
For more information about how to add code, see <cocos2d-x for WP7> Use box2d for collision detection (and only used for collision detection ). In fact, it is similar. Here I will explain what I have done, and I will also provide a sample code later.

First, I added the same declaration as in the collision detection article, world creation and other operations, and added tags for player, projectile, and enemy for collision detection, the addboxbodyforsprite method is also added. Tick method. Perform the same operations on collision detection. When the player and enemy collide, the system jumps to gameoverscene to display you lose. In setplayerposition, add a check item in the food collection area. If the number of samples is 8, you will be redirected to show you win. (I have counted 8 on my map ).

This completes. Box2d detection is really convenient. Sample Code download: http://dl.dbank.com/c0rr5l1b7p

Part2: Common Detection

The normal method is to use the position and contentsize of the genie to generate a rectangle for detection.
Then, add the variable declaration to the tilemaplayer class:

        List<CCSprite> enemies;        List<CCSprite> projectiles;

Then, in init, the initial list is:

            //init the list            enemies = new List<CCSprite>();            projectiles = new List<CCSprite>();

Add the following code at the end of the addenemyatxy method:

enemies.Add(enemy);

Then, add the following code to the tilemaplayer class:

        void testCollision(float dt)        {            List<CCSprite> projectilesToDelete = new List<CCSprite>();            List<CCSprite> targetToDelete = new List<CCSprite>();            //iterate through projectilesforeach (var projectile in projectiles)            {                CCRect projectileRect = new CCRect(                    projectile.position.x - projectile.contentSize.width / 2,                    projectile.position.y - projectile.contentSize.height / 2,                    projectile.contentSize.width,                    projectile.contentSize.height);                                //iterate through enemies,see if any intersect with current projectile                foreach (var target in enemies)                {                    CCRect targetRect = new CCRect(                        target.position.x - target.contentSize.width / 2,                        target.position.y - target.contentSize.width / 2,                        target.contentSize.width,                        target.contentSize.height);                    if (CCRect.CCRectIntersetsRect(projectileRect,targetRect))                    {                        targetToDelete.Add(target);                    }                }                //delete all hit enemies                foreach (var target in targetToDelete)                {                    enemies.Remove(target);                    this.removeChild(target,true);                }                if (targetToDelete.Count > 0)                {                    //add the projectile to the list of ones to remove                    projectilesToDelete.Add(projectile);                }                targetToDelete.Clear();            }            //remove all the projectiles that hit            foreach (var projectile in projectilesToDelete)            {                projectiles.Remove(projectile);                this.removeChild(projectile, true);            }            projectilesToDelete.Clear();        }

Then add the following code:

// at the end of the launch projectiles section of ccTouchEnded:withEvent:projectiles.Add(projectile);// at the end of projectileMoveFinished:projectiles.Remove(sprite);//in the initthis.schedule(testCollision);

All the code above, about how it works, can be found on my blog "using cocos2d-x to do a simple Windows Phone 7 game (a)" tutorial. Of course, the comments in the original author's article are clearer, so I hope you will discuss more about the translation tutorials. The Code should be knocked in by hand as much as possible. Do not worry, ALT + C, ALT + V. This is not good, really!
Now, you can use a dart to hit the enemy, and they will disappear after being hit. Now let's add some logic so that the game can win or fail!
Add a method:

        void gameOver(bool isWin)        {            GameOverScene gameOverScene = new GameOverScene(isWin);            CCDirector.sharedDirector().replaceScene(gameOverScene);        }

Then add a check item in setplayerposition to collect the food. If the number is 8, you will be redirected to show you win. (I have counted 8 on my map ).

                        if (numCollected == 2)                        {                            gameOver(true);                        }

In this tutorial, the game is over if one of our players hits him. Add a column loop in the testcollision method of the class:

            foreach (var target in enemies)            {                CCRect targetRect = new CCRect(                    target.position.x - target.contentSize.width / 2,                    target.position.y - target.contentSize.width / 2,                    target.contentSize.width,                    target.contentSize.height);                if (CCRect.CCRectContainsPoint(targetRect, player.position))                {                    gameOver(false);                }            }

Compile and run the program to get the expected results.

Sample Code: http://dl.dbank.com/c0xy82fc3w

What should we do next?
Suggestion:
Add multiple levels
Add different types of enemies
Displays blood records and player life on the HUD Layer
Make more items, such as blood and weapons.
For a menu system, you can select a level, disable sound effects, and so on.
Use a better user interface to make the game picture more exquisite and throw darts more chic.
In addition, continue: <cocos2d-x for WP7> using cocos2d-x to make tile map-based games: different battles (turn-based battles) (4 ).

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.