mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-01-28 07:22:21 -08:00
Hover unit display
This commit is contained in:
parent
0aa313e37c
commit
5da0267df9
9 changed files with 144 additions and 95 deletions
|
|
@ -180,6 +180,25 @@ public class Units{
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Returns the closest ally of this team. Filter by predicate.
|
||||
* Unlike the closest() function, this only guarantees that unit hitboxes overlap the range. */
|
||||
public static Unitc closestOverlap(Team team, float x, float y, float range, Boolf<Unitc> predicate){
|
||||
result = null;
|
||||
cdist = 0f;
|
||||
|
||||
nearby(team, x - range, y - range, range*2f, range*2f, e -> {
|
||||
if(!predicate.get(e)) return;
|
||||
|
||||
float dist = e.dst2(x, y);
|
||||
if(result == null || dist < cdist){
|
||||
result = e;
|
||||
cdist = dist;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Iterates over all units in a rectangle. */
|
||||
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
|
||||
teamIndex.tree(team).intersect(height, x, y, width, cons);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import arc.graphics.g2d.*;
|
|||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.math.geom.QuadTree.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
|
|
@ -37,7 +38,7 @@ import static mindustry.Vars.*;
|
|||
|
||||
@EntityDef(value = {Tilec.class}, isFinal = false, genio = false, serialize = false)
|
||||
@Component
|
||||
abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTreeObject{
|
||||
abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTreeObject, Displayable{
|
||||
//region vars and initialization
|
||||
static final float timeToSleep = 60f * 1;
|
||||
static final ObjectSet<Tilec> tmpTiles = new ObjectSet<>();
|
||||
|
|
@ -910,7 +911,18 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
|
|||
return block.icon(Cicon.medium);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
//display the block stuff
|
||||
//TODO duplicated code?
|
||||
table.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(block.getDisplayIcon(tile))).size(8 * 4);
|
||||
t.labelWrap(block.getDisplayName(tile)).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
|
||||
table.row();
|
||||
|
||||
table.table(bars -> {
|
||||
bars.defaults().growX().height(18f).pad(4);
|
||||
|
||||
|
|
@ -926,12 +938,13 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
|
|||
|
||||
if(items != null){
|
||||
table.row();
|
||||
table.left();
|
||||
table.table(l -> {
|
||||
Bits current = new Bits();
|
||||
l.left();
|
||||
|
||||
Runnable rebuild = () -> {
|
||||
l.clearChildren();
|
||||
l.left();
|
||||
for(Item item : content.items()){
|
||||
if(items.hasFlowItem(item)){
|
||||
l.image(item.icon(Cicon.small)).padRight(3f);
|
||||
|
|
@ -950,7 +963,7 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
|
|||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}).left();
|
||||
}
|
||||
|
||||
if(liquids != null){
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ package mindustry.entities.comp;
|
|||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
|
|
@ -13,13 +14,14 @@ import mindustry.game.EventType.*;
|
|||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc{
|
||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable{
|
||||
|
||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor;
|
||||
|
||||
|
|
@ -187,6 +189,11 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
type.display(this, table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImmune(StatusEffect effect){
|
||||
return type.immunities.contains(effect);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import arc.graphics.*;
|
|||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
|
|
@ -99,6 +100,27 @@ public class UnitType extends UnlockableContent{
|
|||
|
||||
public void landed(Unitc unit){}
|
||||
|
||||
public void display(Unitc unit, Table table){
|
||||
table.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(icon(Cicon.medium))).size(8 * 4);
|
||||
t.labelWrap(localizedName).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
table.row();
|
||||
|
||||
table.table(bars -> {
|
||||
bars.defaults().growX().height(18f).pad(4);
|
||||
|
||||
bars.add(new Bar("blocks.health", Pal.health, unit::healthf).blink(Color.white));
|
||||
bars.row();
|
||||
|
||||
if(state.rules.unitAmmo){
|
||||
bars.add(new Bar("blocks.ammo", Pal.ammo, () -> (float)unit.ammo() / ammoCapacity));
|
||||
bars.row();
|
||||
}
|
||||
}).growX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayUnit(table, this);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ public class LoadoutDialog extends BaseDialog{
|
|||
this.updater = updater;
|
||||
this.capacity = capacity;
|
||||
this.hider = hider;
|
||||
//this.filter = filter;
|
||||
show();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@ import arc.scene.style.*;
|
|||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.type.*;
|
||||
|
|
@ -32,12 +33,11 @@ public class PlacementFragment extends Fragment{
|
|||
boolean[] categoryEmpty = new boolean[Category.all.length];
|
||||
ObjectMap<Category,Block> selectedBlocks = new ObjectMap<>();
|
||||
ObjectFloatMap<Category> scrollPositions = new ObjectFloatMap<>();
|
||||
Block hovered, lastDisplay;
|
||||
Tile lastHover;
|
||||
Tile hoverTile;
|
||||
Block menuHoverBlock;
|
||||
Object lastDisplayState;
|
||||
boolean wasHovered;
|
||||
Table blockTable, toggler, topTable;
|
||||
ScrollPane blockPane;
|
||||
boolean lastGround;
|
||||
boolean blockSelectEnd;
|
||||
int blockSelectSeq;
|
||||
long blockSelectSeqMillis;
|
||||
|
|
@ -234,10 +234,10 @@ public class PlacementFragment extends Fragment{
|
|||
}
|
||||
});
|
||||
|
||||
button.hovered(() -> hovered = block);
|
||||
button.hovered(() -> menuHoverBlock = block);
|
||||
button.exited(() -> {
|
||||
if(hovered == block){
|
||||
hovered = null;
|
||||
if(menuHoverBlock == block){
|
||||
menuHoverBlock = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -260,27 +260,32 @@ public class PlacementFragment extends Fragment{
|
|||
frame.table(Tex.buttonEdge2,top -> {
|
||||
topTable = top;
|
||||
top.add(new Table()).growX().update(topTable -> {
|
||||
|
||||
//find current hovered thing
|
||||
Displayable hovered = hovered();
|
||||
Block displayBlock = menuHoverBlock != null ? menuHoverBlock : control.input.block;
|
||||
Object displayState = displayBlock != null ? displayBlock : hovered;
|
||||
boolean isHovered = displayBlock == null; //use hovered thing if displayblock is null
|
||||
|
||||
//don't refresh unnecessarily
|
||||
if((tileDisplayBlock() == null && lastDisplay == getSelected() && !lastGround)
|
||||
|| (tileDisplayBlock() != null && lastHover == hoverTile && lastDisplay == tileDisplayBlock() && lastGround))
|
||||
return;
|
||||
//refresh only when the hover state changes, or the displayed block changes
|
||||
if(wasHovered == isHovered && lastDisplayState == displayState) return;
|
||||
|
||||
topTable.clear();
|
||||
topTable.top().left().margin(5);
|
||||
|
||||
lastHover = hoverTile;
|
||||
lastDisplay = getSelected();
|
||||
lastGround = tileDisplayBlock() != null;
|
||||
lastDisplayState = displayState;
|
||||
wasHovered = isHovered;
|
||||
|
||||
if(lastDisplay != null){ //show selected recipe
|
||||
lastGround = false;
|
||||
//show details of selected block, with costs
|
||||
if(displayBlock != null){
|
||||
|
||||
topTable.table(header -> {
|
||||
String keyCombo = "";
|
||||
if(!mobile && Core.settings.getBool("blockselectkeys")){
|
||||
Seq<Block> blocks = getByCategory(currentCategory);
|
||||
for(int i = 0; i < blocks.size; i++){
|
||||
if(blocks.get(i) == lastDisplay && (i + 1) / 10 - 1 < blockSelect.length){
|
||||
if(blocks.get(i) == displayBlock && (i + 1) / 10 - 1 < blockSelect.length){
|
||||
keyCombo = Core.bundle.format("placement.blockselectkeys", Core.keybinds.get(blockSelect[currentCategory.ordinal()]).key.toString())
|
||||
+ (i < 10 ? "" : Core.keybinds.get(blockSelect[(i + 1) / 10 - 1]).key.toString() + ",")
|
||||
+ Core.keybinds.get(blockSelect[i % 10]).key.toString() + "]";
|
||||
|
|
@ -290,13 +295,13 @@ public class PlacementFragment extends Fragment{
|
|||
}
|
||||
final String keyComboFinal = keyCombo;
|
||||
header.left();
|
||||
header.add(new Image(lastDisplay.icon(Cicon.medium))).size(8 * 4);
|
||||
header.labelWrap(() -> !unlocked(lastDisplay) ? Core.bundle.get("block.unknown") : lastDisplay.localizedName + keyComboFinal)
|
||||
header.add(new Image(displayBlock.icon(Cicon.medium))).size(8 * 4);
|
||||
header.labelWrap(() -> !unlocked(displayBlock) ? Core.bundle.get("block.unknown") : displayBlock.localizedName + keyComboFinal)
|
||||
.left().width(190f).padLeft(5);
|
||||
header.add().growX();
|
||||
if(unlocked(lastDisplay)){
|
||||
if(unlocked(displayBlock)){
|
||||
header.button("?", Styles.clearPartialt, () -> {
|
||||
ui.content.show(lastDisplay);
|
||||
ui.content.show(displayBlock);
|
||||
Events.fire(new BlockInfoEvent());
|
||||
}).size(8 * 5).padTop(-5).padRight(-5).right().grow().name("blockinfo");
|
||||
}
|
||||
|
|
@ -306,7 +311,7 @@ public class PlacementFragment extends Fragment{
|
|||
topTable.table(req -> {
|
||||
req.top().left();
|
||||
|
||||
for(ItemStack stack : lastDisplay.requirements){
|
||||
for(ItemStack stack : displayBlock.requirements){
|
||||
req.table(line -> {
|
||||
line.left();
|
||||
line.image(stack.item.icon(Cicon.small)).size(8 * 2);
|
||||
|
|
@ -326,34 +331,21 @@ public class PlacementFragment extends Fragment{
|
|||
}
|
||||
}).growX().left().margin(3);
|
||||
|
||||
if(!lastDisplay.isPlaceable() || !player.isBuilder()){
|
||||
if(!displayBlock.isPlaceable() || !player.isBuilder()){
|
||||
topTable.row();
|
||||
topTable.table(b -> {
|
||||
b.image(Icon.cancel).padRight(2).color(Color.scarlet);
|
||||
b.add(!player.isBuilder() ? "$unit.nobuild" : lastDisplay.unplaceableMessage()).width(190f).wrap();
|
||||
b.add(!player.isBuilder() ? "$unit.nobuild" : displayBlock.unplaceableMessage()).width(190f).wrap();
|
||||
b.left();
|
||||
}).padTop(2).left();
|
||||
}
|
||||
|
||||
}else if(tileDisplayBlock() != null){ //show selected tile
|
||||
lastDisplay = tileDisplayBlock();
|
||||
topTable.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(lastDisplay.getDisplayIcon(hoverTile))).size(8 * 4);
|
||||
t.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
if(hoverTile.team() == player.team()){
|
||||
topTable.row();
|
||||
topTable.table(t -> {
|
||||
t.left().defaults().left();
|
||||
if(hoverTile.entity != null){
|
||||
hoverTile.entity.display(t);
|
||||
}
|
||||
}).left().growX();
|
||||
}
|
||||
}else if(hovered != null){
|
||||
//show hovered item, whatever that may be
|
||||
hovered.display(topTable);
|
||||
}
|
||||
});
|
||||
}).colspan(3).fillX().visible(() -> getSelected() != null || tileDisplayBlock() != null).touchable(Touchable.enabled);
|
||||
}).colspan(3).fillX().visible(this::hasInfoBox).touchable(Touchable.enabled);
|
||||
frame.row();
|
||||
frame.image().color(Pal.gray).colspan(3).height(4).growX();
|
||||
frame.row();
|
||||
|
|
@ -425,28 +417,15 @@ public class PlacementFragment extends Fragment{
|
|||
}
|
||||
|
||||
Seq<Block> getByCategory(Category cat){
|
||||
returnArray.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.category == cat && block.isVisible()){
|
||||
returnArray.add(block);
|
||||
}
|
||||
}
|
||||
return returnArray;
|
||||
return returnArray.selectFrom(content.blocks(), block -> block.category == cat && block.isVisible());
|
||||
}
|
||||
|
||||
Seq<Block> getUnlockedByCategory(Category cat){
|
||||
returnArray.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.category == cat && block.isVisible() && unlocked(block)){
|
||||
returnArray.add(block);
|
||||
}
|
||||
}
|
||||
returnArray.sort((b1, b2) -> {
|
||||
return returnArray.selectFrom(content.blocks(), block -> block.category == cat && block.isVisible() && unlocked(block)).sort((b1, b2) -> {
|
||||
int locked = -Boolean.compare(unlocked(b1), unlocked(b2));
|
||||
if(locked != 0) return locked;
|
||||
return Boolean.compare(!b1.isPlaceable(), !b2.isPlaceable());
|
||||
});
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
Block getSelectedBlock(Category cat){
|
||||
|
|
@ -460,41 +439,38 @@ public class PlacementFragment extends Fragment{
|
|||
return !state.isCampaign() || data.isUnlocked(block);
|
||||
}
|
||||
|
||||
/** Returns the currently displayed block in the top box. */
|
||||
Block getSelected(){
|
||||
Block toDisplay = null;
|
||||
boolean hasInfoBox(){
|
||||
return control.input.block != null || menuHoverBlock != null || hovered() != null;
|
||||
}
|
||||
|
||||
/** Returns the thing being hovered over. */
|
||||
@Nullable
|
||||
Displayable hovered(){
|
||||
Vec2 v = topTable.stageToLocalCoordinates(Core.input.mouse());
|
||||
|
||||
//setup hovering tile
|
||||
if(!Core.scene.hasMouse() && topTable.hit(v.x, v.y, false) == null){
|
||||
hoverTile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(hoverTile != null && hoverTile.entity != null){
|
||||
//if the mouse intersects the table or the UI has the mouse, no hovering can occur
|
||||
if(Core.scene.hasMouse() || topTable.hit(v.x, v.y, false) != null) return null;
|
||||
|
||||
//check for a unit
|
||||
Unitc unit = Units.closestOverlap(player.team(), Core.input.mouseWorldX(), Core.input.mouseWorldY(), 5f, u -> !u.isLocal());
|
||||
//if cursor has a unit, display it
|
||||
if(unit != null) return unit;
|
||||
|
||||
//check tile being hovered over
|
||||
Tile hoverTile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||
if(hoverTile != null){
|
||||
//if the tile has an entity, display it
|
||||
if(hoverTile.entity != null){
|
||||
hoverTile.entity.updateFlow(true);
|
||||
return hoverTile.entity;
|
||||
}
|
||||
|
||||
//if the tile has a drop, display the drop
|
||||
if(hoverTile.drop() != null){
|
||||
return hoverTile;
|
||||
}
|
||||
}else{
|
||||
hoverTile = null;
|
||||
}
|
||||
|
||||
//block currently selected
|
||||
if(control.input.block != null){
|
||||
toDisplay = control.input.block;
|
||||
}
|
||||
|
||||
//block hovered on in build menu
|
||||
if(hovered != null){
|
||||
toDisplay = hovered;
|
||||
}
|
||||
|
||||
return toDisplay;
|
||||
}
|
||||
|
||||
/** Returns the block currently being hovered over in the world. */
|
||||
Block tileDisplayBlock(){
|
||||
return hoverTile == null ? null :
|
||||
hoverTile.block().synthetic() ? hoverTile.block() :
|
||||
hoverTile.drop() != null && hoverTile.block() == Blocks.air ?
|
||||
hoverTile.overlay().itemDrop != null ? hoverTile.overlay() :
|
||||
hoverTile.floor() : null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import arc.graphics.g2d.TextureAtlas.*;
|
|||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.Seq;
|
||||
import arc.struct.EnumSet;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import arc.func.*;
|
|||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.math.geom.QuadTree.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
|
|
@ -11,11 +13,12 @@ import mindustry.content.*;
|
|||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Tile implements Position, QuadTreeObject{
|
||||
public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
static final ObjectSet<Tilec> tileSet = new ObjectSet<>();
|
||||
|
||||
/** Tile traversal cost. */
|
||||
|
|
@ -583,6 +586,17 @@ public class Tile implements Position, QuadTreeObject{
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
Block toDisplay = overlay.itemDrop != null ? overlay : floor;
|
||||
|
||||
table.table(t -> {
|
||||
t.left();
|
||||
t.add(new Image(toDisplay.getDisplayIcon(this))).size(8 * 4);
|
||||
t.labelWrap(toDisplay.getDisplayName(this)).left().width(190f).padLeft(5);
|
||||
}).growX().left();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getX(){
|
||||
return drawx();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||
archash=30796daec8eba235f9cde3723537431df4e4f6f5
|
||||
archash=06c938d6dced0d9bf9f8ec98d4767b38f633f8fa
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue