How to Use libgdx to compile a simple game (2)-complete

Source: Internet
Author: User
Tags gety libgdx

The previous article introduced the preparation of the prototype of the game. This article will improve some logic and add more effects.

The sample code can be found at https://github.com/htynkn/dartsshasha. if you have any permission, download the response in the tagfile.

Improve the dart Logic

The current darts can be rotated to fly, but there is a problem that cannot be solved.

First, the speed of the dart. If the user's touch is very close to the left side, the speed of the dart will be very slow.

Second, if you touch the center position, the dart should fly in that direction by default, instead of flying to the touch position and then disappear.

The solution here is very simple, that is, to calculate a value of 480 X based on the user's touch position, so that the darts can fly to the rightmost side, while maintaining a considerable speed.

In the createProjectile method, add

Float r = (target. y-image. getY ()/(target. x-image. getX (); // obtain the slope float detY = r * 480; // obtain the variation of Y image. addAction (Actions. moveTo (480 + image. getX (), detY + image. getY (), 2f); // sets the movement of the dart.

In this way, the problem is basically solved.

Next, let's take a look at the number and corresponding positions of darts.

First, the speed of the darts must be limited. Otherwise, what is the significance of the full screen darts. The maximum number of darts is 5.

Add at the beginning of touchDown

If (projectiles. getChildren (). size> = 5) {// limit the number of darts to 5 return false ;}

 

In this way, no new darts will be generated when the number of darts on the screen is greater than or equal to 5.

There is also the position of the touch. If the touch is too right, there will be a problem of the dart flying or the speed is too fast, so when the touch is too close to the left side, the dart will not be released.

Add in the touchDown Method

If (vector3.x <man. getX () + 5) {// return false if the touch is too close to the left ;}

 

Here, 5 is what I wrote casually, which only represents a meaning. After testing, I thought 5 was too small. Finally I changed it to 10.

More appealing opponent

To be honest, the current opponent is moving at a constant speed. Let's first improve its appearance.

I'm from http://untamed.wild-refuge.net/rmxpresources.php? Characters obtains the image.

Package and put it in the assets folder.

Because libgdx only has the default Animation class, but cannot be used directly in stage, create a new Scythe class and inherit the Actor class.

Public Scythe (AtlasRegion atlasRegion) {super (); this. setWidth (titleWidth); // set the height of this. setHeight (titleHeight); // set the width of TextureRegion [] [] temp = atlasRegion. split (titleWidth, titleHeight); // frames = new TextureRegion [4]; // obtain the four frames of the second row for (int I = 0; I <4; I ++) {animated frames [I] = temp [1] [I];} animation = new Animation (0.1f, animated frames); // create an animation with a frame interval of 0.1}

Because the source image is 200 in width and 192 in height, a total of 16 images are displayed. Therefore, the width of each image is 50 and the height is 48. To use the Animation class, you must manually provide the relevant frames and obtain the frames through the Animation and the current time.

The method to override draw is as follows:

@ Overridepublic void draw (SpriteBatch batch, float parentAlpha) {stateTime + = Gdx. graphics. getDeltaTime (); // get the total time currentFrame = animation. getKeyFrame (stateTime, true); // obtain the current key frame batch. draw (currentFrame, this. getX (), this. getY (), this. getWidth (), this. getHeight (); // draw}

 

Modify the region. getRegionHeight () Section of TargetGroup by dividing all by 4. Modify the Image class Scythe class at the same time.

The complete Scythe is as follows:

Package com. cnblogs. htynkn; import com. badlogic. gdx. gdx; import com. badlogic. gdx. graphics. g2d. animation; import com. badlogic. gdx. graphics. g2d. spriteBatch; import com. badlogic. gdx. graphics. g2d. textureAtlas. atlasRegion; import com. badlogic. gdx. graphics. g2d. textureRegion; import com. badlogic. gdx. scenes. scene2d. actor; public class Scythe extends Actor {TextureRegion [] extends frames; // save every frame of Animation animation; // Animation float stateTime; // total time TextureRegion currentFrame; // The current frame int titleWidth = 50; // The Block width int titleHeight = 48; // The declared block height public Scythe (AtlasRegion atlasRegion) {super (); this. setWidth (titleWidth); // set the height of this. setHeight (titleHeight); // set the width of TextureRegion [] [] temp = atlasRegion. split (titleWidth, titleHeight); // frames = new TextureRegion [4]; // obtain the four frames of the second row for (int I = 0; I <4; I ++) {animated frames [I] = temp [1] [I];} animation = new Animation (0.1f, animated frames); // create an animation, frame interval 0.1} @ Overridepublic void draw (SpriteBatch batch, float parentAlpha) {stateTime + = Gdx. graphics. getDeltaTime (); // get the total time currentFrame = animation. getKeyFrame (stateTime, true); // obtain the current key frame batch. draw (currentFrame, this. getX (), this. getY (), this. getWidth (), this. getHeight (); // draw }}

 

The effect is as follows:

Add blood records

Let's try to give the monster the amount of blood, that is, some monsters can withstand two injuries. Here we will use basic things.

The first is the location of the blood strip. Generally, it should be displayed in red on the top of the monster.

There are many ways to draw. I am not used to the set of mesh, so here I use the Pixmap class.

Add two variables to the Sythe class first.

Int margin = 2; // interval between the blood bar and the character int pixHeight = 5; // blood Bar Height

Then add

Pixmap pixmap = new Pixmap (64, 8, Format. RGBA8888); // generates a 64*8 image pixmap. setColor (Color. BLACK); // set the color to BLACK pixmap. drawRectangle (0, 0, titleWidth, pixHeight); // draw the border Texture pixmaptex = new Texture (pixmap); // generate the image TextureRegion pix = new TextureRegion (pixmaptex, titleWidth, pixHeight); // cut the image batch. draw (pix, this. getX (), this. getY () + this. titleHeight + this. margin); // draw

In this way, we have a black border.

Then there is the filling of the blood volume. Two variables are added to record the total blood volume and the current blood volume.

Int maxHp; // total blood volume int currentHp; // current blood volume

Add the code for drawing the blood bar to the statement after the Black Box is drawn.

Pixmap. setColor (Color. RED); // set the Color to RED pixmap. fillRectangle (0, 1, titleWidth * currentHp/maxHp, pixHeight-2); // draw blood records

Finally, you must release pixmap.

pixmap.dispose();

This is the effect of setting the total blood volume to 2 and the current blood volume to 1.

Control Conversion

After increasing the blood volume, our code also needs to be modified. In the main class DartsShaSha, modify the relevant logic.

For convenience, we assign the game logic to the Controller.

Create an IController first

package com.cnblogs.htynkn.controller;import com.badlogic.gdx.scenes.scene2d.Group;import com.badlogic.gdx.scenes.scene2d.Stage;public abstract class IController extends Group {public abstract void update(Stage stage);}

 

Create a TargetController class and override the update method. In this method, we can process the related logic. Then, in the main class, we only need to call the method.

First, copy the existing code in, and then add two methods in Sythe to handle the damage and death judgments.

Public void beAttacked (int damage) {if (this. currentHp> damage) {// if the volume of blood exceeds the damage level, the response value currentHp = currentHp-damage is deducted;} else if (this. currentHp> 0) {// if the volume of blood is less than the damage but there is still a volume of blood, set the blood volume to currentHp = 0;} public Boolean isAlive () {return this. currentHp> 0 ;}

 

Then add the update code to TargetController.

 

Public void update (Stage stage) {Group projectiles = (Group) stage. getRoot (). findActor ("projectiles"); // obtain the GroupActor [] projectile = projectiles. getChildren (). begin (); Actor [] targets = this. getChildren (). begin (); for (int I = 0; I <projectiles. getChildren (). size; I ++) {Actor actor = projectile [I]; for (int j = 0; j <this. getChildren (). size; j ++) {Actor target = targets [j]; if (ProjectileFactory . AttackAlive (target, actor) {Scythe scythe = (Scythe) target; scythe. beAttacked (1); projectiles. removeActor (actor); if (! Scythe. isAlive () {this. removeActor (target) ;}break ;}}}}

 

Modify the instantiation code in the main class and call the update method in render.

TargetController. update (this. stage); // call the update method to process the monster Logic

 

The effect is as follows:

 

Darts lethal and Gesture Recognition

In the code above, the lethal effect of each dart is 1, and the blood volume of each monster is 2.

Now let's modify the control of the darts so that the darts can also be handled using the controller.

In this example, the screen is set to be touched to launch a general dart and the lethal force is 1. The lethal effect after a long press is 2.

Libgdx provides an interface for Gesture Recognition. Here I select to inherit from GestureAdapter.

public class DartsListener extends GestureAdapter

At the same time, modify the dart control to the controller mode and create the Controller DartsController.

The Code is as follows:

Package com. cnblogs. htynkn. controller; import com. badlogic. gdx. graphics. g2d. textureAtlas. atlasRegion; import com. badlogic. gdx. math. rectangle; import com. badlogic. gdx. scenes. scene2d. actor; import com. badlogic. gdx. scenes. scene2d. stage; import com. badlogic. gdx. scenes. scene2d. actions. actions; import com. cnblogs. htynkn. elements. dart; public class DartsController extends IController {AtlasRegion region; @ Overrid Epublic void update (Stage stage) {// If the Dart has flown in, escape the Actor [] projectile = this. getChildren (). begin (); for (int j = 0; j <this. getChildren (). size; j ++) {Actor actor = projectile [j]; if (! This. checkAlive (actor) {this. removeActor (actor) ;}} public DartsController (AtlasRegion region) {this. region = region;} public void AddDarts (Dart dart) {if (this. getChildren (). size> = 5) {// return if the number of darts is greater than or equal to 5;} float r = (dart. getTarget (). y-dart. getY ()/(dart. getTarget (). x-dart. getX (); // obtain the slope float detY = r * 480; // obtain the variation of Y in dart. addAction (Actions. moveTo (480 + dart. getX (), detY + dart. getY (), 2f); // set the move of the Dart this. addActor (dart);} public Boolean attackAlive (Actor target, Actor projectile) {Rectangle rectangle = new Rectangle (target. getX (), target. getY (), target. getWidth (), target. getHeight (); // create a rectangle return rectangle. contains (projectile. getX () + projectile. getWidth ()/2, projectile. getY () + projectile. getHeight ()/2); // determines whether it is in the matrix, that is, whether it hits} public Boolean checkAlive (Actor projectile) {if (projectile. getActions (). size = 1) {return false;} return true;} public Dart createDart () {return new Dart (region );}}

The Dart code is as follows:

package com.cnblogs.htynkn.elements;import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;import com.badlogic.gdx.math.Vector2;import com.badlogic.gdx.scenes.scene2d.actions.Actions;import com.badlogic.gdx.scenes.scene2d.ui.Image;public class Dart extends Image {Vector2 target;public Dart(AtlasRegion region) {super(region);this.setOrigin(getWidth() / 2, getHeight() / 2);this.addAction(Actions.repeat(50, Actions.rotateBy(360, 0.5f)));}public void setTarget(Vector2 target) {this.target = target;}public void setTarget(float x, float y) {this.target = new Vector2(x, y);}public Vector2 getTarget() {return target;}}

 

Because our input is processed by another class DartsListener, the inheritance of modifying the main class is as follows:

public class DartsShaSha implements ApplicationListener

 

Add our new gesture reader to multiplexer.

GestureDetector gestureDetector = new GestureDetector (new DartsListener (this. stage); multiplexer. addProcessor (gestureDetector); // Add Gesture Recognition

The current DartsListener code is as follows:

 

Package com. cnblogs. htynkn. listener; import com. badlogic. gdx. input. gestureDetector. gestureAdapter; import com. badlogic. gdx. math. vector3; import com. badlogic. gdx. scenes. scene2d. actor; import com. badlogic. gdx. scenes. scene2d. stage; import com. cnblogs. htynkn. controller. dartsController; import com. cnblogs. htynkn. elements. dart; public class DartsListener extends GestureAdapter {Stage stage; public DartsListener (Stage stage) {this. stage = stage ;}@ Overridepublic boolean touchDown (float x, float y, int pointer, int button) {DartsController dartsController = (DartsController) stage. getRoot (). findActor ("dartsController"); if (dartsController. getChildren (). size> = 5) {// limit the number of darts to 5 return false;} Vector3 vector3 = new Vector3 (x, y, 0); stage. getCamera (). unproject (vector3); // coordinate conversion Actor man = stage. getRoot (). findActor ("player"); if (vector3.x <man. getX () + 10) {// return false if the touch is too close to the left;} Dart dart = dartsController. createDart (); dart. setX (man. getX () + man. getWidth ()/2); dart. setY (man. getY () + man. getHeight ()/2); dart. setTarget (vector3.x, vector3.y); dartsController. addDarts (dart); return true ;}@ Overridepublic boolean longPress (float x, float y) {return true ;}}

Other details may be modified. For details, refer to the code.

Currently, we can only reconstruct the game, but the game effect has not changed. Now we can set the lethal force and long-pressed processing of darts.

Add attributes to Dart

int power;

Add in instantiation

Power = 1; // The default Lethal force is 1.

Set

scythe.beAttacked(1);

 

Change

scythe.beAttacked(dart.getPower());

 

The longPress method in is basically the same as the touchDown method, but

Dart. setPower (2); // set the lethal effect to 2dart. setColor (Color. RED); // set it to RED

Let's take a look at the processing process. When you touch the screen, the tap event is triggered first, the touchDown event is triggered, and the longPress event is finally triggered.

That is, at present, our game will generate a general dart with a long click, and then our red dart.

To solve this problem, we add a DartsDetector class that inherits the GestureDetector class.

Because the event trigger sequence is tap-> touchdown-> longpress-> touchup.

Therefore, all our Event Logic is transferred to touchup. If it is a longpress event, a red dart is triggered, and if it is a touchdown, a general dart is triggered.

Because our DartsListener does not process any logic, it deletes all the code.

The code in GestureDetector is as follows:

Package com. cnblogs. htynkn. listener; import com. badlogic. gdx. graphics. color; import com. badlogic. gdx. input. gestureDetector; import com. badlogic. gdx. math. vector3; import com. badlogic. gdx. scenes. scene2d. actor; import com. badlogic. gdx. scenes. scene2d. stage; import com. cnblogs. htynkn. controller. dartsController; import com. cnblogs. htynkn. elements. dart; public class DartsDetector extends GestureDetector {Stage stage; public DartsDetector (Stage stage Stage, GestureListener listener) {super (listener); this. stage = stage ;}@ Overridepublic boolean touchUp (float x, float y, int pointer, int button) {DartsController dartsController = (DartsController) stage. getRoot (). findActor ("dartsController"); if (dartsController. getChildren (). size> = 5) {// limit the number of darts to 5 return false;} Vector3 vector3 = new Vector3 (x, y, 0); stage. getCamera (). unproject (vector3); // coordinate conversion Actor man = stage. getRoot (). findActor ("player"); if (vector3.x <man. getX () + 10) {// returns super if the touch is too close to the left. touchUp (x, y, pointer, button);} Dart dart = dartsController. createDart (); dart. setX (man. getX () + man. getWidth ()/2); dart. setY (man. getY () + man. getHeight ()/2); dart. setTarget (vector3.x, vector3.y); if (this. isLongPressed () {// if it is a long press, it turns into a red dart. setPower (2); // set the lethal effect to 2dart. setColor (Color. RED); // set to RED} dartsController. addDarts (dart); return super. touchUp (x, y, pointer, button );}}

 

The effect is as follows:

Conclusion

This article has modified a lot of details, but it may be a small part but the key changes are not marked in the text. For example, set a name for the Actor to be obtained using the findActor method.

If there is a problem with the direct replication, you can obtain https://github.com/htynkn/dartsshashafrom the git library, and the corresponding tagis page2.

Apk address is http://pan.baidu.com/share/link? Consumer id = 331455 & uk = 4127624209

In the next article, some sound effects and resource loading will be added, and a statistical function will be added.

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.