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.