本教程将实现角色技能攻击释放和NPC受到攻击掉血的效果。
来看下效果:
预先准备NPC、技能和字体素材,位图字体准备两种效果,字体大的可以显示暴击掉血效果
场景代码
package com.mygdx.game.battle.screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.mygdx.game.battle.BattleDemo;
import java.util.Random;
public class BattleScreen implements Screen {
private BattleDemo game;
private OrthographicCamera camera;
private Viewport viewport;
private TextureAtlas atlas;
private TextureAtlas spriteAtlas;
private Animation<TextureAtlas.AtlasRegion> wolfWalkAnim;
private Animation<TextureAtlas.AtlasRegion> wolfAttackAnim;
private Animation<TextureAtlas.AtlasRegion> wolfSkillAnim;
private Animation<TextureAtlas.AtlasRegion> pigWalkAnim;
private TextureAtlas.AtlasRegion pigScaredRegion;
private TextureAtlas.AtlasRegion pigDeadRegion;
private Rectangle pigRect;
private Rectangle skillRect;
private BitmapFont bitmapFont;
private BitmapFont bigBitmapFont;
private float wolfStateTime = 0;
private float wolfAttackStateTime = 0;
private float wolfSkillStateTime = 0;
private float pigStateTime = 0;
private float pigScaredTime = 0;
private float bloodDisplayTime = 0;
private boolean isAttacking = false;
private boolean isPigBeingAttack = false;
private boolean debug = false;
private Random random = new Random();
private int bloodReduce;
public BattleScreen(BattleDemo game){
this.game = game;
atlas = new TextureAtlas(Gdx.files.internal("battle/battle.atlas"));
spriteAtlas = new TextureAtlas(Gdx.files.internal("battle/sprites.atlas"));
bitmapFont = new BitmapFont(Gdx.files.internal("bitmapfont.fnt"), false);
bigBitmapFont = new BitmapFont(Gdx.files.internal("bitmapfont_big.fnt"), false);
camera = new OrthographicCamera();
viewport = new FitViewport(BattleDemo.V_WIDTH, BattleDemo.V_HEIGHT, camera);
//wolf walking
Array<TextureAtlas.AtlasRegion> wolfRegions = atlas.findRegions("wolf");
Array<TextureAtlas.AtlasRegion> frames = new Array<>();
for (int i = 0; i < 4; i++) {
frames.add(wolfRegions.get(i));
}
wolfWalkAnim = new Animation(0.2f, frames, Animation.PlayMode.LOOP);
//wolf attack
frames.clear();
for (int i = 7; i < 9; i++) {
frames.add(wolfRegions.get(i));
}
wolfAttackAnim = new Animation(0.2f, frames, Animation.PlayMode.NORMAL);
//skill
Array<TextureAtlas.AtlasRegion> skillRegions = atlas.findRegions("effect_n");
skillRegions.reverse();
wolfSkillAnim = new Animation(0.1f, skillRegions, Animation.PlayMode.NORMAL);
//pig
Array<TextureAtlas.AtlasRegion> pigRegions = spriteAtlas.findRegions("pig");
frames.clear();
for (int i = 0; i < 3; i++) {
frames.add(pigRegions.get(i));
}
pigWalkAnim = new Animation(0.2f, frames, Animation.PlayMode.LOOP);
pigScaredRegion = pigRegions.get(3);
pigDeadRegion = pigRegions.get(4);
}
@Override
public void show() {
}
private void handleInput() {
//按J键攻击
if(Gdx.input.isKeyJustPressed(Input.Keys.J)){
attack();
}
}
private boolean handleCollision(Rectangle rectangle1, Rectangle rectangle2) {
//简单使用判断矩形是否重叠来做碰撞检测
if(rectangle1 == null || rectangle2 == null){
return false;
}
return rectangle1.overlaps(rectangle2);
}
public void attack(){
isAttacking = true;
}
@Override
public void render(float delta) {
ScreenUtils.clear(Color.BLACK);
camera.update();
handleInput();
game.batch.begin();
if(isAttacking){
//狼NPC攻击动作
wolfAttackStateTime += delta;
TextureAtlas.AtlasRegion keyFrame = wolfAttackAnim.getKeyFrame(wolfAttackStateTime);
if(!keyFrame.isFlipX()){
keyFrame.flip(true, false);
}
game.batch.draw(keyFrame, 0, 0);
if(debug)
drawDebug(0, 0, keyFrame.getRegionWidth(), keyFrame.getRegionHeight());
//攻击动作完后显示技能效果
if(wolfAttackAnim.isAnimationFinished(wolfAttackStateTime)){
wolfSkillStateTime += delta;
TextureAtlas.AtlasRegion skillRegion = wolfSkillAnim.getKeyFrame(wolfSkillStateTime);
if(!skillRegion.isFlipX()){
skillRegion.flip(true, false);
}
//技能随时间向右位移一段距离
Float x = 40 + wolfSkillStateTime * 1000;
game.batch.draw(skillRegion, x, 15);
//获取技能帧图矩形,用以和猪做碰撞检测
skillRect = new Rectangle(x, 15, skillRegion.getRegionWidth(), skillRegion.getRegionHeight());
if(handleCollision(pigRect, skillRect)){
pigScaredTime = 0;
isPigBeingAttack = true;
//一旦和猪发生碰撞,将矩形设置为null防止多次触发碰撞事件
pigRect = null;
skillRect = null;
//随机产生掉血值
bloodReduce = random.nextInt(1000) + 100;
}
if(debug)
drawDebug(x.intValue(), 15, skillRegion.getRegionWidth(), skillRegion.getRegionHeight());
}
}else{
//狼不攻击的时候默认播放行走动作
wolfStateTime += delta;
TextureAtlas.AtlasRegion keyFrame = wolfWalkAnim.getKeyFrame(wolfStateTime);
//狼的纹理默认是面向左边的,因此需要翻转
if(!keyFrame.isFlipX()){
keyFrame.flip(true, false);
}
game.batch.draw(keyFrame, 0, 0);
if(debug)
drawDebug(0, 0, keyFrame.getRegionWidth(), keyFrame.getRegionHeight());
}
//pig
if(isPigBeingAttack){
//播放猪收到攻击的纹理帧
game.batch.draw(pigScaredRegion, 350, 0);
pigScaredTime += delta;
if(debug)
drawDebug(350, 0, pigScaredRegion.getRegionWidth(), pigScaredRegion.getRegionHeight());
}else{
//猪默认播放行走动作
pigStateTime += delta;
TextureAtlas.AtlasRegion pigRegion = pigWalkAnim.getKeyFrame(pigStateTime);
game.batch.draw(pigRegion, 350, 0);
pigRect = new Rectangle(350, 0, pigRegion.getRegionWidth(), pigRegion.getRegionHeight());
//fot debug
if(debug)
drawDebug(350, 0, pigRegion.getRegionWidth(), pigRegion.getRegionHeight());
}
//display blood reduce effect
if(isPigBeingAttack){
//猪受到攻击显示掉血效果
float alpha = (100 - bloodDisplayTime * 100) / 100;
bitmapFont.setColor(1, 1, 1, alpha);
float y = pigScaredRegion.getRegionHeight() + 20 + bloodDisplayTime * 100;
//模拟暴击掉血效果
if(bloodReduce > 600){
bigBitmapFont.draw(game.batch, "" + bloodReduce, 340, y);
}else{
bitmapFont.draw(game.batch, "" + bloodReduce, 340, y);
}
bloodDisplayTime += delta;
}else{
bloodDisplayTime = 0;
}
game.batch.end();
if(pigScaredTime > 0.5){
isPigBeingAttack = false;
}
//技能播放完后重置变量值
if(wolfSkillAnim.isAnimationFinished(wolfSkillStateTime)){
isAttacking = false;
wolfAttackStateTime = 0;
wolfSkillStateTime = 0;
}
}
//绘制DEBUG矩形框
private void drawDebug(int x, int y, int width, int height){
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.GREEN);
pixmap.drawRectangle(0, 0, width, height);
//TODO need to dispose
game.batch.draw(new Texture(pixmap), x, y);
}
@Override
public void resize(int width, int height) {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void hide() {
}
@Override
public void dispose() {
atlas.dispose();
spriteAtlas.dispose();
bitmapFont.dispose();
}
}
游戏入口类
package com.mygdx.game.battle;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.mygdx.game.battle.screens.BattleScreen;
public class BattleDemo extends Game {
public static final int V_WIDTH = 800;
public static final int V_HEIGHT = 400;
public SpriteBatch batch;
@Override
public void create() {
batch = new SpriteBatch();
setScreen(new BattleScreen(this));
}
@Override
public void render() {
super.render();
}
}