Added a visual indicator of selected hand and added scroll actions

This commit is contained in:
OLEGSHA 2021-08-30 21:33:01 +03:00
parent 040a4f7fd7
commit e7d0e8fe40
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
2 changed files with 197 additions and 85 deletions

View 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()));
}
}

View File

@ -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;
};
}
}