Added a visual indicator of selected hand and added scroll actions
This commit is contained in:
parent
040a4f7fd7
commit
e7d0e8fe40
110
src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
Normal file
110
src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.test.inv;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
|
||||
public class HandSlots extends Component {
|
||||
|
||||
private final SlotComponent left;
|
||||
private final SlotComponent right;
|
||||
|
||||
/**
|
||||
* Right is 0, left is 1
|
||||
*/
|
||||
private float selection = 0;
|
||||
private static final float ANIMATION_SPEED = 10f;
|
||||
|
||||
public HandSlots(String name, SlotComponent left, SlotComponent right) {
|
||||
super(name);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
|
||||
addChild(left);
|
||||
addChild(right);
|
||||
setLayout(null);
|
||||
|
||||
centerAtOrigin(left);
|
||||
centerAtOrigin(right);
|
||||
layoutSelf();
|
||||
}
|
||||
|
||||
private static void centerAtOrigin(Component component) {
|
||||
Vec2i size = component.getPreferredSize();
|
||||
component.setBounds(-size.x / 2, -size.y / 2, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleChildren(RenderTarget target) {
|
||||
|
||||
Renderable leftRenderable = left.assembleToRenderable();
|
||||
Renderable rightRenderable = right.assembleToRenderable();
|
||||
|
||||
target.addCustomRenderer(renderer -> {
|
||||
|
||||
tickAnimation();
|
||||
|
||||
renderer.pushTransform().translate(
|
||||
(float) InputTracker.getCursorX(),
|
||||
(float) InputTracker.getCursorY(),
|
||||
0
|
||||
);
|
||||
|
||||
if (selection > 0.5) {
|
||||
renderHand(renderer, leftRenderable, selection, -1);
|
||||
renderHand(renderer, rightRenderable, 1 - selection, +1);
|
||||
} else {
|
||||
renderHand(renderer, rightRenderable, 1 - selection, +1);
|
||||
renderHand(renderer, leftRenderable, selection, -1);
|
||||
}
|
||||
|
||||
renderer.popTransform();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private float stretch(float t, float zero, float one) {
|
||||
return zero * (1 - t) + one * t;
|
||||
}
|
||||
|
||||
private void renderHand(ShapeRenderHelper renderer, Renderable renderable, float selected, float direction) {
|
||||
|
||||
float offsetX = direction * stretch(selected, 40, 0);
|
||||
float offsetY = direction * stretch(selected, 30, 0);
|
||||
float scale = selected < 0.5 ? stretch(selected * 2, 0.6f, 1.0f) : 1;
|
||||
|
||||
renderer.pushTransform().translate(offsetX, offsetY, 0).scale(scale);
|
||||
renderable.render(renderer);
|
||||
renderer.popTransform();
|
||||
|
||||
}
|
||||
|
||||
private void tickAnimation() {
|
||||
float desired = InventoryScreen.isLeftHandSelected() ? 1 : 0;
|
||||
float difference = selection - desired;
|
||||
selection += difference * (1 - Math.exp(ANIMATION_SPEED * GraphicsInterface.getFrameLength()));
|
||||
}
|
||||
|
||||
}
|
@ -22,21 +22,19 @@ import java.util.function.Supplier;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Components;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.common.Units;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||
import ru.windcorp.progressia.common.world.item.ItemContainer;
|
||||
import ru.windcorp.progressia.common.world.item.ItemSlot;
|
||||
@ -44,44 +42,27 @@ import ru.windcorp.progressia.common.world.item.Items;
|
||||
|
||||
public class InventoryScreen extends Component {
|
||||
|
||||
public static class CursorFollower extends Component {
|
||||
|
||||
public CursorFollower(Component child) {
|
||||
super("CursorFollower");
|
||||
addChild(child);
|
||||
setLayout(null);
|
||||
|
||||
Vec2i size = child.getPreferredSize();
|
||||
child.setBounds(-size.x / 2, -size.y / 2, size);
|
||||
layoutSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleChildren(RenderTarget target) {
|
||||
Renderable renderable = getChildren().get(0).assembleToRenderable();
|
||||
|
||||
target.addCustomRenderer(renderer -> {
|
||||
renderer.pushTransform().translate(
|
||||
(float) InputTracker.getCursorX(),
|
||||
(float) InputTracker.getCursorY(),
|
||||
0
|
||||
);
|
||||
|
||||
renderable.render(renderer);
|
||||
|
||||
renderer.popTransform();
|
||||
|
||||
});
|
||||
}
|
||||
private static final double MIN_PICK_ALL_DELAY = Units.get("0.5 s");
|
||||
|
||||
public static boolean isLeftHandSelected() {
|
||||
return InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
|
||||
|| InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL);
|
||||
}
|
||||
|
||||
private final ItemContainer leftHand;
|
||||
private final ItemContainer rightHand;
|
||||
private final InventoryComponent mainInventory;
|
||||
|
||||
private double lastLeftClick = Double.NEGATIVE_INFINITY;
|
||||
private ItemSlot lastLeftClickSlot = null;
|
||||
|
||||
public InventoryScreen(String name, InventoryComponent mainInventory, EntityDataPlayer player) {
|
||||
super(name);
|
||||
|
||||
this.mainInventory = mainInventory;
|
||||
this.leftHand = player.getLeftHand();
|
||||
this.rightHand = player.getRightHand();
|
||||
|
||||
setLayout(new LayoutFill(0));
|
||||
|
||||
addChild(new Panel(name + ".Background", new LayoutAlign(10), Colors.toVector(0x66000000), null));
|
||||
@ -90,47 +71,14 @@ public class InventoryScreen extends Component {
|
||||
mainInventoryPanel.addChild(mainInventory);
|
||||
addChild(Components.center(mainInventoryPanel));
|
||||
|
||||
this.leftHand = player.getLeftHand();
|
||||
this.rightHand = player.getRightHand();
|
||||
addChild(new CursorFollower(createHands(name, leftHand, rightHand)));
|
||||
|
||||
addListeners(mainInventory);
|
||||
}
|
||||
|
||||
private Component createHands(String name, ItemContainer leftHand, ItemContainer rightHand) {
|
||||
|
||||
SlotComponent leftComponent = new SlotComponent(name + ".HandLeft", leftHand, 0);
|
||||
SlotComponent rightComponent = new SlotComponent(name + ".HandRight", rightHand, 0);
|
||||
|
||||
final int gap = 15;
|
||||
final int offset = 60;
|
||||
addChild(new HandSlots(name + ".Hands", leftComponent, rightComponent));
|
||||
|
||||
Component hands = new Group(name + ".Hands", null, leftComponent, rightComponent);
|
||||
hands.setLayout(new Layout() {
|
||||
addListeners(mainInventory);
|
||||
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
Vec2i leftSize = leftComponent.getPreferredSize();
|
||||
Vec2i rightSize = rightComponent.getPreferredSize();
|
||||
|
||||
leftComponent.setBounds(c.getX(), c.getY(), leftSize);
|
||||
rightComponent.setBounds(c.getX() + leftSize.x + gap, c.getY() + offset, rightSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec2i calculatePreferredSize(Component c) {
|
||||
Vec2i leftSize = leftComponent.getPreferredSize();
|
||||
Vec2i rightSize = rightComponent.getPreferredSize();
|
||||
|
||||
return new Vec2i(
|
||||
leftSize.x + gap + rightSize.x,
|
||||
Math.max(leftSize.y + offset, rightSize.y + offset)
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return hands;
|
||||
mainInventory.focusNext();
|
||||
}
|
||||
|
||||
private void addListeners(InventoryComponent mainInventory) {
|
||||
@ -138,18 +86,14 @@ public class InventoryScreen extends Component {
|
||||
ItemSlot left = leftHand.getSlot(0);
|
||||
ItemSlot right = rightHand.getSlot(0);
|
||||
|
||||
Supplier<ItemSlot> handSlot = () -> {
|
||||
boolean hasCtrl = InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
|
||||
|| InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL);
|
||||
|
||||
return hasCtrl ? left : right;
|
||||
};
|
||||
Supplier<ItemSlot> handSlot = () -> isLeftHandSelected() ? left : right;
|
||||
|
||||
Consumer<BasicButton> pickAll = createPickAllAction(handSlot);
|
||||
|
||||
for (DecoratedSlotComponent component : mainInventory.getSlots()) {
|
||||
component.addAction(pickAll);
|
||||
component.addListener(KeyEvent.class, createRMBAction(component.getSlot(), handSlot));
|
||||
component.addListener(WheelScrollEvent.class, createWheelAction(component.getSlot(), handSlot));
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,17 +103,53 @@ public class InventoryScreen extends Component {
|
||||
ItemSlot handSlot = handSlotChooser.get();
|
||||
ItemSlot invSlot = ((DecoratedSlotComponent) button).getSlot();
|
||||
|
||||
if (Items.pour(handSlot, invSlot) == 0) {
|
||||
if (!Items.swap(handSlot, invSlot)) {
|
||||
return;
|
||||
}
|
||||
boolean success = false;
|
||||
|
||||
double now = GraphicsInterface.getTime();
|
||||
if (lastLeftClickSlot == invSlot && now - lastLeftClick < MIN_PICK_ALL_DELAY) {
|
||||
|
||||
lastLeftClickSlot = null;
|
||||
lastLeftClick = Double.NEGATIVE_INFINITY;
|
||||
|
||||
pickAll(handSlot);
|
||||
|
||||
success = true;
|
||||
|
||||
} else {
|
||||
lastLeftClick = now;
|
||||
lastLeftClickSlot = invSlot;
|
||||
}
|
||||
|
||||
requestReassembly();
|
||||
if (!success && !leftHand.getSlot(0).isEmpty() && rightHand.getSlot(0).isEmpty()) {
|
||||
success = Items.pour(leftHand.getSlot(0), invSlot) != 0;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
success = Items.pour(handSlot, invSlot) != 0;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
success = Items.swap(handSlot, invSlot);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
requestReassembly();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void pickAll(ItemSlot handSlot) {
|
||||
for (DecoratedSlotComponent component : mainInventory.getSlots()) {
|
||||
|
||||
Items.pour(component.getSlot(), handSlot);
|
||||
if (handSlot.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private InputListener<KeyEvent> createRMBAction(ItemSlot invSlot, Supplier<ItemSlot> handSlotChooser) {
|
||||
return input -> {
|
||||
|
||||
@ -202,4 +182,26 @@ public class InventoryScreen extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private InputListener<WheelScrollEvent> createWheelAction(ItemSlot invSlot, Supplier<ItemSlot> handSlotChooser) {
|
||||
return input -> {
|
||||
|
||||
if (!input.hasVerticalMovement()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemSlot handSlot = handSlotChooser.get();
|
||||
|
||||
ItemSlot from = input.isDown() ? handSlot : invSlot;
|
||||
ItemSlot into = input.isDown() ? invSlot : handSlot;
|
||||
|
||||
if (Items.pour(from, into, 1) != 0) {
|
||||
requestReassembly();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user