Radial tech tree layout
This commit is contained in:
@@ -23,7 +23,8 @@ import io.anuke.mindustry.graphics.*;
|
|||||||
import io.anuke.mindustry.io.SaveIO.*;
|
import io.anuke.mindustry.io.SaveIO.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
import io.anuke.mindustry.ui.TreeLayout.*;
|
import io.anuke.mindustry.ui.layout.*;
|
||||||
|
import io.anuke.mindustry.ui.layout.TreeLayout.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ public class DeployDialog extends FloatingDialog{
|
|||||||
|
|
||||||
ZoneNode root = new ZoneNode(Zones.groundZero, null);
|
ZoneNode root = new ZoneNode(Zones.groundZero, null);
|
||||||
|
|
||||||
TreeLayout layout = new TreeLayout();
|
BranchTreeLayout layout = new BranchTreeLayout();
|
||||||
layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f);
|
layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f);
|
||||||
layout.gapBetweenNodes = Scl.scl(120f);
|
layout.gapBetweenNodes = Scl.scl(120f);
|
||||||
layout.layout(root);
|
layout.layout(root);
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ import io.anuke.mindustry.gen.*;
|
|||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
import io.anuke.mindustry.ui.TreeLayout.*;
|
import io.anuke.mindustry.ui.layout.*;
|
||||||
|
import io.anuke.mindustry.ui.layout.TreeLayout.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -101,13 +102,10 @@ public class TechTreeDialog extends FloatingDialog{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void treeLayout(){
|
void treeLayout(){
|
||||||
TreeLayout layout = new TreeLayout();
|
RadialTreeLayout layout = new RadialTreeLayout();
|
||||||
layout.gapBetweenLevels = Scl.scl(60f);
|
|
||||||
layout.gapBetweenNodes = Scl.scl(40f);
|
|
||||||
LayoutNode node = new LayoutNode(root, null);
|
LayoutNode node = new LayoutNode(root, null);
|
||||||
layout.layout(node);
|
layout.layout(node);
|
||||||
bounds.set(layout.getBounds());
|
//bounds.y += nodeSize*1.5f;
|
||||||
bounds.y += nodeSize*1.5f;
|
|
||||||
copyInfo(node);
|
copyInfo(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +154,7 @@ public class TechTreeDialog extends FloatingDialog{
|
|||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.width = this.height = nodeSize;
|
this.width = this.height = nodeSize;
|
||||||
if(node.children != null){
|
if(node.children != null){
|
||||||
children = Array.with(node.children).select(n -> n.visible).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class);
|
children = Array.with(node.children).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.anuke.mindustry.ui;
|
package io.anuke.mindustry.ui.layout;
|
||||||
|
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
@@ -6,7 +6,7 @@ import io.anuke.arc.math.geom.*;
|
|||||||
/**
|
/**
|
||||||
* Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>.
|
* Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>.
|
||||||
*/
|
*/
|
||||||
public class TreeLayout{
|
public class BranchTreeLayout implements TreeLayout{
|
||||||
public TreeLocation rootLocation = TreeLocation.top;
|
public TreeLocation rootLocation = TreeLocation.top;
|
||||||
public TreeAlignment alignment = TreeAlignment.awayFromRoot;
|
public TreeAlignment alignment = TreeAlignment.awayFromRoot;
|
||||||
public float gapBetweenLevels = 10;
|
public float gapBetweenLevels = 10;
|
||||||
@@ -18,6 +18,7 @@ public class TreeLayout{
|
|||||||
private float boundsTop = Float.MAX_VALUE;
|
private float boundsTop = Float.MAX_VALUE;
|
||||||
private float boundsBottom = Float.MIN_VALUE;
|
private float boundsBottom = Float.MIN_VALUE;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void layout(TreeNode root){
|
public void layout(TreeNode root){
|
||||||
firstWalk(root, null);
|
firstWalk(root, null);
|
||||||
calcSizeOfLevels(root, 0);
|
calcSizeOfLevels(root, 0);
|
||||||
@@ -288,20 +289,4 @@ public class TreeLayout{
|
|||||||
public enum TreeAlignment{
|
public enum TreeAlignment{
|
||||||
center, towardsRoot, awayFromRoot
|
center, towardsRoot, awayFromRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TreeNode<T extends TreeNode>{
|
|
||||||
public float width, height, x, y;
|
|
||||||
|
|
||||||
//should be initialized by user
|
|
||||||
public T[] children;
|
|
||||||
public T parent;
|
|
||||||
|
|
||||||
private float mode, prelim, change, shift;
|
|
||||||
private int number = -1;
|
|
||||||
private TreeNode thread, ancestor;
|
|
||||||
|
|
||||||
boolean isLeaf(){
|
|
||||||
return children == null || children.length == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
65
core/src/io/anuke/mindustry/ui/layout/RadialTreeLayout.java
Normal file
65
core/src/io/anuke/mindustry/ui/layout/RadialTreeLayout.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package io.anuke.mindustry.ui.layout;
|
||||||
|
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.math.*;
|
||||||
|
|
||||||
|
public class RadialTreeLayout implements TreeLayout{
|
||||||
|
public float startRadius, delta;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layout(TreeNode root){
|
||||||
|
startRadius = root.height * 2.4f;
|
||||||
|
delta = root.height * 2.4f;
|
||||||
|
|
||||||
|
bfs(root, true);
|
||||||
|
radialize(root, 0, 360);
|
||||||
|
}
|
||||||
|
|
||||||
|
void radialize(TreeNode root, float from, float to){
|
||||||
|
int depthOfVertex = root.number;
|
||||||
|
float theta = from;
|
||||||
|
float radius = startRadius + (delta * depthOfVertex);
|
||||||
|
|
||||||
|
int leavesNumber = bfs(root, false);
|
||||||
|
for(TreeNode child : root.children){
|
||||||
|
int lambda = bfs(child, false);
|
||||||
|
float mi = theta + ((float)lambda / leavesNumber * (to - from));
|
||||||
|
|
||||||
|
float x = radius * Mathf.cos((theta + mi) / 2f * Mathf.degRad);
|
||||||
|
float y = radius * Mathf.sin((theta + mi) / 2f * Mathf.degRad);
|
||||||
|
|
||||||
|
child.x = x;
|
||||||
|
child.y = y;
|
||||||
|
|
||||||
|
if(child.children.length > 0){
|
||||||
|
radialize(child, theta, mi);
|
||||||
|
}
|
||||||
|
theta = mi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bfs(TreeNode node, boolean assign){
|
||||||
|
if(assign) node.number = 0;
|
||||||
|
ObjectSet<TreeNode> visited = new ObjectSet<>();
|
||||||
|
Queue<TreeNode> queue = new Queue<>();
|
||||||
|
int leaves = 0;
|
||||||
|
|
||||||
|
visited.add(node);
|
||||||
|
queue.addFirst(node);
|
||||||
|
|
||||||
|
while(!queue.isEmpty()){
|
||||||
|
TreeNode current = queue.removeFirst();
|
||||||
|
if(current.children.length == 0) leaves++;
|
||||||
|
|
||||||
|
for(TreeNode child : current.children){
|
||||||
|
if(assign) child.number = current.number + 1;
|
||||||
|
if(!visited.contains(child)){
|
||||||
|
visited.add(child);
|
||||||
|
queue.addLast(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return leaves;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
core/src/io/anuke/mindustry/ui/layout/TreeLayout.java
Normal file
22
core/src/io/anuke/mindustry/ui/layout/TreeLayout.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package io.anuke.mindustry.ui.layout;
|
||||||
|
|
||||||
|
public interface TreeLayout{
|
||||||
|
void layout(TreeNode root);
|
||||||
|
|
||||||
|
class TreeNode<T extends TreeNode>{
|
||||||
|
public float width, height, x, y;
|
||||||
|
|
||||||
|
//should be initialized by user
|
||||||
|
public T[] children;
|
||||||
|
public T parent;
|
||||||
|
|
||||||
|
//internal stuff
|
||||||
|
public float mode, prelim, change, shift;
|
||||||
|
public int number = -1, ancestors;
|
||||||
|
public TreeNode thread, ancestor;
|
||||||
|
|
||||||
|
public boolean isLeaf(){
|
||||||
|
return children == null || children.length == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user