package org.test.towerdefense;
import loon.LSystem;
import loon.Screen;
import loon.action.ActionBind;
import loon.action.ActionListener;
import loon.action.FadeTo;
import loon.action.MoveTo;
import loon.action.map.Field2D;
import loon.action.sprite.StatusBar;
import loon.canvas.Canvas;
import loon.canvas.Image;
import loon.canvas.LColor;
import loon.component.Actor;
import loon.component.ActorLayer;
import loon.component.LLayer;
import loon.component.LPaper;
import loon.event.GameTouch;
import loon.font.LFont;
import loon.opengl.GLEx;
import loon.utils.ArrayMap;
import loon.utils.ConfigReader;
import loon.utils.MathUtils;
import loon.utils.TArray;
import loon.utils.timer.LTimerContext;
public class TDScreen extends Screen {
private int selectTurret = -1;
private Field2D field;
private String[] turrets = new String[] { "assets/bulletTurret.png",
"assets/bombTurret.png", "assets/poisonTurret.png",
"assets/laserTurret.png", "assets/bullet.png" };
/**
* 子弹用类
*
*/
class Bullet extends Actor {
/* 抛物线用加速度、重力 */
private float vx, vy, gravity;
/* 增加一个type向,用来区分子弹类型 */
int type;
private float speed;
private float dir;
private int damage;
private float x, y;
private boolean removeFlag;
public Bullet(int type, String fileName, float dir, int damage) {
this.setFlag("Bullet");
this.type = type;
this.dir = dir;
this.damage = damage;
this.setImage(fileName);
this.setDelay(50);
/* 如果子弹类型为抛物线 */
if (type == 1) {
this.setDelay(0);
this.speed = 200f;
this.gravity = 200f;
// 转化方向(360度方向)为弧度
float angle = MathUtils.toRadians(this.dir);
// 计算加速度
this.vx = speed * MathUtils.cos(angle);
this.vy = speed * MathUtils.sin(angle);
}
}
protected void addLayer(ActorLayer layer) {
this.x = this.getX();
this.y = this.getY();
}
public void action(long t) {
if (removeFlag) {
return;
}
Object o = null;
switch (type) {
case 0:
for (int i = 0; i < 6; i++) {
// 矫正弹道位置
float angle = MathUtils.toRadians(this.dir);
this.x += MathUtils.cos(angle);
this.y += MathUtils.sin(angle);
}
this.setLocation(
this.x + (field.getTileWidth() - this.getWidth()) / 2,
this.y + (field.getTileHeight() - this.getHeight()) / 2);
break;
case 1:
/*
* 计算每次子弹位置(这个例子如果直接做抛物线,有一处不妥,即MapLayer的setDelay被设定成了500
* 也就是每隔500毫秒(半秒),才改变一次地图中物体状态,这样做出来的抛物线会不太自然。)
*/
x = getX();
y = getY();
float dt = MathUtils.max((t / 1000), 0.01f);
vy += gravity * dt;
x += vx * dt;
y += vy * dt;
this.setLocation(this.x, this.y);
break;
}
o = this.getOnlyCollisionObject("Enemy");
// 当与敌相撞时
if (o != null) {
Enemy e = (Enemy) o;
// 减少敌方HP
e.hp -= this.damage;
e.hpBar.setUpdate(e.hp);
removeFlag = true;
// 从Layer中删除自身
getLLayer().removeObject(this);
return;
// 超出游戏画面时删除自身
} else if (this.getX() <= 12
|| this.getX() >= this.getLLayer().getWidth() - 12
|| this.getY() <= 12
|| this.getY() >= this.getLLayer().getHeight() - 12) {
removeFlag = true;
this.getLLayer().removeObject(this);
}
}
}
/**
* 炮塔用类
*
*/
class Turret extends Actor {
private int range = 50;
private int delay = 10;
boolean selected;
public Turret(String fileName) {
this.setFlag("Turret");
setImage(fileName);
setDelay(100);
setAlpha(0);
}
public void addLayer(ActorLayer layer) {
// 让角色渐进式出现
FadeTo fade = fadeIn();
// 监听渐进淡出事件
fade.setActionListener(new ActionListener() {
public void process(ActionBind o) {
}
public void start(ActionBind o) {
}
// 当渐进完毕时
public void stop(ActionBind o) {
// 旋转90度
rotateTo(90);
}
});
}
public void draw(GLEx g) {
if (selected) {
g.saveBrush();
g.setColor(255, 0, 0, 100);
g.fillOval(-(range * 2 - field.getTileWidth()) / 2,
-(range * 2 - field.getTileHeight()) / 2,
this.range * 2 - 1, this.range * 2 - 1);
g.setColor(LColor.red);
g.drawOval(-(range * 2 - field.getTileWidth()) / 2,
-(range * 2 - field.getTileHeight()) / 2,
this.range * 2 - 1, this.range * 2 - 1);
g.restoreBrush();
}
}
public void action(long t) {
// 遍历指定半径内所有Enemy类
TArray<Actor> es = this.getCollisionObjects(this.range, "Enemy");
// 当敌人存在
if (!es.isEmpty()) {
Enemy target = (Enemy) es.get(0);
// 删除原有炮台事件
removeActionEvents();
// 旋转炮台对准Enemy坐标
setRotation(MathUtils.toDegrees(MathUtils.atan2(
(target.getY() - this.getY()),
(target.getX() - this.getX()))));
}
// 延迟炮击
if (this.delay > 0) {
--this.delay;
} else if (!es.isEmpty()) {
// *将子弹类型设定为1*/
// 构造炮弹
Bullet bullet = new Bullet(0, turrets[4], this.getRotation(), 2);
// 计算炮击点
int x = MathUtils.round(MathUtils.cos(MathUtils.toRadians(this
.getRotation())) * (float) bullet.getWidth() * 2)
+ this.x();
int y = MathUtils.round(MathUtils.sin(MathUtils.toRadians(this
.getRotation())) * (float) bullet.getHeight() * 2)
+ this.y();
// 注入炮弹到Layer
this.getLLayer().addObject(bullet, x, y);
this.delay = 10;
}
}
}
/**
* 敌兵用类
*
*/
class Enemy extends Actor {
private int startX, startY;
private int endX, endY;
private int speed, hp;
private boolean removeFlag;
// 使用精灵StatusBar充当血槽
protected StatusBar hpBar;
public Enemy(String fileName, int sx, int sy, int ex, int ey,
int speed, int hp) {
this.setFlag("Enemy");
this.setDelay(300);
this.setImage(fileName);
this.hpBar = new StatusBar(hp, hp, (this.width() - 25) / 2,
this.height() + 5, 25, 5);
this.startX = sx;
this.startY = sy;
this.endX = ex;
this.endY = ey;
this.speed = speed;
this.hp = hp;
}
public void draw(GLEx g) {
// 绘制精灵
hpBar.createUI(g);
}
public void action(long t) {
// 触发精灵事件
hpBar.update(t);
if (hp <= 0 && !removeFlag) {
// 设定死亡时渐变
FadeTo fade = fadeOut();
// 渐变时间为30毫秒
fade.setSpeed(30);
// 监听渐变过程
fade.setActionListener(new ActionListener() {
public void process(ActionBind o) {
}
public void start(ActionBind o) {
}
public void stop(ActionBind o) {
Enemy.this.removeActionEvents();
Enemy.this.getLLayer().removeObject(Enemy.this);
}
});
this.removeFlag = true;
}
}
// 首次注入Layer时调用此函数
public void addLayer(final ActorLayer layer) {
// 坐标矫正,用以让角色居于瓦片中心
final int offsetX = (getLLayer().getField2D().getTileWidth() - this
.width()) / 2;
final int offsetY = (getLLayer().getField2D().getTileWidth() - this
.height()) / 2;
// 初始化角色在Layer中坐标
setLocation(startX + offsetX, startY + offsetY);
// 命令角色向指定坐标自行移动(参数为false为四方向寻径,为true时八方向),并返回移动控制器
// PS:endX与endY非显示位置,所以不必矫正
final MoveTo move = moveTo(endX, endY, false);
// 矫正坐标,让角色居中
move.setOffset(offsetX, offsetY);
// 启动角色事件监听
move.setActionListener(new ActionListener() {
// 截取事件进行中数据
public void process(ActionBind o) {
// 获得角色移动方向
switch (move.getDirection()) {
case Field2D.TUP:
// 根据当前移动方向,变更角色旋转方向(以下同)
o.setRotation(270);
break;
case Field2D.TLEFT:
o.setRotation(180);
break;
case Field2D.TRIGHT:
o.setRotation(0);
break;
case Field2D.TDOWN:
o.setRotation(90);
break;
default:
break;
}
}
public void start(ActionBind o) {
}
// 当角色移动完毕时
public void stop(ActionBind o) {
// 从Layer中删除此角色
layer.removeObject((Actor) o);
}
});
// 设定移动速度
move.setSpeed(speed);
}
}
// 起始点
class Begin extends Actor {
public Begin(String fileName) {
setImage(fileName);
}
}
// 结束点
class End extends Actor {
public End(String fileName) {
setImage(fileName);
}
}
/**
* 拖拽用菜单
*
*/
class Menu extends LLayer {
public Menu() {
super(128, 240);
// 设定menu层级高于MapLayer
setLayer(101);
// 不锁定menu移动
setLocked(false);
setLimitMove(false);
// 锁定Actor拖拽
setActorDrag(false);
setDelay(500);
// 设定Menu背景
Image image = Image.createImage(this.width(), this.height());
Canvas g = image.getCanvas();
g.setColor(0, 0, 0, 125);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(LColor.white);
g.setFont(LFont.getFont(15));
g.drawText("我是可拖拽菜单", 12, 25);
setBackground(image.texture());
image.close();
LPaper bulletTurret = new LPaper(turrets[0]) {
// 当选中当前按钮时,为按钮绘制选中框(以下同)
public void paint(GLEx g) {
if (selectTurret == 0) {
g.setColor(LColor.red);
g.drawRect(2, 2, this.getWidth() - 4,
this.getHeight() - 4);
g.resetColor();
}
}
public void downClick() {
selectTurret = 0;
}
};
bulletTurret.setLocation(18, 64);
LPaper bombTurret = new LPaper(turrets[1]) {
public void paint(GLEx g) {
if (selectTurret == 1) {
g.setColor(LColor.red);
g.drawRect(2, 2, this.getWidth() - 4,
this.getHeight() - 4);
g.resetColor();
}
}
public void downClick() {
selectTurret = 1;
}
};
bombTurret.setLocation(78, 64);
LPaper poisonTurret = new LPaper(turrets[2]) {
public void paint(GLEx g) {
if (selectTurret == 2) {
g.setColor(LColor.red);
g.drawRect(2, 2, this.getWidth() - 4,
this.getHeight() - 4);
g.resetColor();
}
}
public void downClick() {
selectTurret = 2;
}
};
poisonTurret.setLocation(18, 134);
LPaper laserTurret = new LPaper(turrets[3]) {
public void paint(GLEx g) {
if (selectTurret == 3) {
g.setColor(LColor.red);
g.drawRect(2, 2, this.getWidth() - 4,
this.getHeight() - 4);
g.resetColor();
}
}
public void downClick() {
selectTurret = 3;
}
};
laserTurret.setLocation(78, 134);
// 用LPaper制作敌人增加按钮
LPaper button = new LPaper("assets/button.png") {
public void downClick() {
// 获得MapLayer
MapLayer layer = (MapLayer) getBottomLayer();
// 开始游戏演算
layer.doStart();
}
};
button.setLocation(27, 196);
// 复合LPaper到Layer
add(bulletTurret);
add(bombTurret);
add(poisonTurret);
add(laserTurret);
add(button);
}
public void downClick(int x, int y) {
selectTurret = -1;
}
}
/**
* 大地图用Layer
*/
class MapLayer extends LLayer {
private boolean start;
private int startX, startY, endX, endY;
private int index, count;
// 设置MapLayer背景元素(键值需要与map.txt文件中标识相对应)
private final ArrayMap pathMap = new ArrayMap();
public MapLayer() {
super(576, 480, true);
// 不锁定MapLayer拖拽
setLocked(false);
// 锁定MapLayer中角色拖拽
setActorDrag(false);
pathMap.put(0, Image.createImage("assets/sand.png"));
pathMap.put(1, Image.createImage("assets/sandTurn1.png"));
pathMap.put(2, Image.createImage("assets/sandTurn2.png"));
pathMap.put(3, Image.createImage("assets/sandTurn3.png"));
pathMap.put(4, Image.createImage("assets/sandTurn4.png"));
pathMap.put(5, new Begin("assets/base.png"));
pathMap.put(6, new End("assets/castle.png"));
ConfigReader config = ConfigReader.getInstance("assets/map.txt");
// 为Layer加入简单的2D地图背景,瓦片大小32x32,以rock图片铺底
setField2DBackground(config.getField2D("test", 32, 32), pathMap,
"assets/rock.png");
TDScreen.this.field = getField2D();
// 敌人出现坐标
this.startX = 64;
this.startY = 416;
// 敌人消失坐标
this.endX = 480;
this.endY = 416;
// 设定MapLayer每隔2秒执行一次内部Action
setDelay(LSystem.SECOND * 2);
}
public void action(long t) {
// 当启动标识为true时执行以下操作
if (start) {
if (index < 3) {
Enemy enemy = null;
// 根据点击next(增加敌人)的次数变换敌人样式
switch (count) {
case 0:
enemy = new Enemy("assets/enemy.png", startX, startY,
endX, endY, 2, 4);
break;
case 1:
enemy = new Enemy("assets/fastEnemy.png", startX,
startY, endX, endY, 4, 6);
break;
case 2:
enemy = new Enemy("assets/smallEnemy.png", startX,
startY, endX, endY, 3, 10);
break;
case 3:
enemy = new Enemy("assets/bigEnemy.png", startX,
startY, endX, endY, 1, 16);
break;
default:
count = 0;
enemy = new Enemy("assets/enemy.png", startX, startY,
endX, endY, 2, 2);
break;
}
addObject(enemy);
index++;
// 否则复位
} else {
start = false;
index = 0;
count++;
}
}
}
private Actor o = null;
public void downClick(int x, int y) {
// 转换鼠标点击区域为数组地图坐标
int newX = x / field.getTileWidth();
int newY = y / field.getTileHeight();
// 当选中炮塔(参数不为-1)且数组地图参数为-1(不可通过)并且无其它角色在此时
if ((o = getClickActor()) == null && selectTurret != -1
&& field.getType(newY, newX) == -1) {
// 添加炮塔
addObject(new Turret(turrets[selectTurret]),
newX * field.getTileWidth(),
newY * field.getTileHeight());
}
if (o != null && o instanceof Turret) {
((Turret) o).selected = true;
}
}
public void upClick(int x, int y) {
if (o != null && o instanceof Turret) {
((Turret) o).selected = false;
}
}
public void doStart() {
this.start = true;
}
}
public void onLoad() {
// 构建地图用Layer
MapLayer layer = new MapLayer();
layer.setAutoDestroy(true);
// 居中
centerOn(layer);
// 添加MapLayer到Screen
add(layer);
// 构建菜单用Layer
Menu menu = new Menu();
// 让menu居于屏幕右侧
rightOn(menu);
menu.setY(0);
// 添加menu到Screen
add(menu);
}
@Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void touchDown(GameTouch e) {
// TODO Auto-generated method stub
}
@Override
public void touchUp(GameTouch e) {
// TODO Auto-generated method stub
}
@Override
public void touchMove(GameTouch e) {
// TODO Auto-generated method stub
}
@Override
public void touchDrag(GameTouch e) {
// TODO Auto-generated method stub
}
@Override
public void resume() {
// TODO Auto-generated method stub
}
@Override
public void pause() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public void draw(GLEx g) {
// TODO Auto-generated method stub
}
@Override
public void alter(LTimerContext timer) {
// TODO Auto-generated method stub
}
}