Pondering too quickly

- Fixed idle instruction only idling for t-1
- Made keyframe skipping a little easier
- Added option to register keyframes as part of a text window builder
- PonderUI now stalls the scene briefly after skips
This commit is contained in:
simibubi 2021-03-12 20:42:37 +01:00
parent 678ddfa764
commit 841bba04bd
7 changed files with 188 additions and 135 deletions

View file

@ -5,150 +5,170 @@ import com.simibubi.create.foundation.gui.widgets.AbstractSimiWidget;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.LerpedFloat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundHandler;
import net.minecraft.client.gui.FontRenderer;
import net.minecraftforge.fml.client.gui.GuiUtils;
import org.antlr.v4.runtime.misc.IntegerList;
public class PonderProgressBar extends AbstractSimiWidget {
LerpedFloat progress;
LerpedFloat flash;
LerpedFloat progress;
LerpedFloat flash;
PonderUI ponder;
PonderUI ponder;
public PonderProgressBar(PonderUI ponder, int xIn, int yIn, int widthIn, int heightIn) {
super(xIn, yIn, widthIn, heightIn);
public PonderProgressBar(PonderUI ponder, int xIn, int yIn, int widthIn, int heightIn) {
super(xIn, yIn, widthIn, heightIn);
this.ponder = ponder;
progress = LerpedFloat.linear()
.startWithValue(0);
flash = LerpedFloat.linear()
.startWithValue(0);
}
this.ponder = ponder;
progress = LerpedFloat.linear()
.startWithValue(0);
flash = LerpedFloat.linear()
.startWithValue(0);
}
public void tick() {
progress.chase(ponder.getActiveScene().getSceneProgress(), .5f, LerpedFloat.Chaser.EXP);
progress.tickChaser();
public void tick() {
progress.chase(ponder.getActiveScene()
.getSceneProgress(), .5f, LerpedFloat.Chaser.EXP);
progress.tickChaser();
if (isHovered)
flash();
}
if (isHovered)
flash();
}
public void flash() {
float value = flash.getValue();
flash.setValue(value + (1 - value) * .2f);
}
public void flash() {
float value = flash.getValue();
flash.setValue(value + (1 - value) * .2f);
}
public void dim() {
float value = flash.getValue();
flash.setValue(value * .5f);
}
public void dim() {
float value = flash.getValue();
flash.setValue(value * .5f);
}
@Override
protected boolean clicked(double mouseX, double mouseY) {
return this.active && this.visible &&
!ponder.getActiveScene().keyframeTimes.isEmpty() &&
mouseX >= (double)this.x &&
mouseX < (double)(this.x + this.width) &&
mouseY >= (double)this.y - 3 &&
mouseY < (double)(this.y + this.height + 3);
}
@Override
protected boolean clicked(double mouseX, double mouseY) {
return this.active && this.visible && !ponder.getActiveScene().keyframeTimes.isEmpty()
&& mouseX >= (double) this.x && mouseX < (double) (this.x + this.width) && mouseY >= (double) this.y - 3
&& mouseY < (double) (this.y + this.height + 20);
}
@Override
public void onClick(double mouseX, double mouseY) {
PonderScene activeScene = ponder.getActiveScene();
int clickedAtTime = (int) ((mouseX - x) / ((double) width) * activeScene.totalTime);
@Override
public void onClick(double mouseX, double mouseY) {
PonderScene activeScene = ponder.getActiveScene();
int clickedAtTime = (int) ((mouseX - x) / ((double) width) * activeScene.totalTime);
int seekTime = 0;
int seekTime = 0;
IntegerList keyframeTimes = activeScene.keyframeTimes;
for (int i = 0; i < keyframeTimes.size(); i++) {
int keyframeTime = keyframeTimes.get(i);
IntegerList keyframeTimes = activeScene.keyframeTimes;
for (int i = 0; i < keyframeTimes.size(); i++) {
int keyframeTime = keyframeTimes.get(i);
if (keyframeTime > clickedAtTime)
break;
if (keyframeTime > clickedAtTime)
break;
seekTime = keyframeTime;
}
ponder.seekToTime(seekTime);
}
seekTime = keyframeTime;
}
ponder.seekToTime(seekTime);
}
public int getHoveredKeyframeIndex(double mouseX) {
PonderScene activeScene = ponder.getActiveScene();
int clickedAtTime = (int) ((mouseX - x) / ((double) width) * activeScene.totalTime);
public int getHoveredKeyframeIndex(double mouseX) {
PonderScene activeScene = ponder.getActiveScene();
int clickedAtTime = (int) ((mouseX - x) / ((double) width) * activeScene.totalTime);
int index = -1;
int index = -1;
IntegerList keyframeTimes = activeScene.keyframeTimes;
for (int i = 0; i < keyframeTimes.size(); i++) {
int keyframeTime = keyframeTimes.get(i);
IntegerList keyframeTimes = activeScene.keyframeTimes;
for (int i = 0; i < keyframeTimes.size(); i++) {
int keyframeTime = keyframeTimes.get(i);
if (keyframeTime > clickedAtTime)
break;
if (keyframeTime > clickedAtTime)
break;
index = i;
}
index = i;
}
return index;
}
return index;
}
@Override
public void renderButton(int mouseX, int mouseY, float partialTicks) {
@Override
public void renderButton(int mouseX, int mouseY, float partialTicks) {
isHovered = clicked(mouseX, mouseY);
isHovered = clicked(mouseX, mouseY);
RenderSystem.pushMatrix();
RenderSystem.translated(0, 0, 400);
PonderUI.renderBox(x, y, width, height, false);
RenderSystem.popMatrix();
RenderSystem.pushMatrix();
RenderSystem.translated(0, 0, 400);
PonderUI.renderBox(x, y, width, height, false);
RenderSystem.popMatrix();
RenderSystem.pushMatrix();
RenderSystem.translated(x - 2, y - 2, 0);
RenderSystem.pushMatrix();
RenderSystem.translated(x - 2, y - 2, 0);
RenderSystem.pushMatrix();
RenderSystem.scaled((width + 4) * progress.getValue(partialTicks), 1, 1);
GuiUtils.drawGradientRect(500, 0, 3, 1, 4, 0x60ffeedd, 0x60ffeedd);
RenderSystem.popMatrix();
RenderSystem.pushMatrix();
RenderSystem.scaled((width + 4) * progress.getValue(partialTicks), 1, 1);
GuiUtils.drawGradientRect(500, 0, 3, 1, 4, 0x80ffeedd, 0x80ffeedd);
GuiUtils.drawGradientRect(500, 0, 4, 1, 5, 0x50ffeedd, 0x50ffeedd);
RenderSystem.popMatrix();
renderKeyframes(mouseX, partialTicks);
renderKeyframes(mouseX, partialTicks);
RenderSystem.popMatrix();
}
RenderSystem.popMatrix();
}
private void renderKeyframes(int mouseX, float partialTicks) {
PonderScene activeScene = ponder.getActiveScene();
private void renderKeyframes(int mouseX, float partialTicks) {
PonderScene activeScene = ponder.getActiveScene();
int hoverStartColor;
int hoverEndColor;
int hoverIndex;
if (isHovered) {
hoverIndex = getHoveredKeyframeIndex(mouseX);
int hoverStartColor;
int hoverEndColor;
int hoverIndex;
float flashValue = flash.getValue(partialTicks) * 3 + (float) Math.sin((AnimationTickHolder.getTicks() + partialTicks) / 6);
if (isHovered) {
hoverIndex = getHoveredKeyframeIndex(mouseX);
float flashValue = flash.getValue(partialTicks) * 3
+ (float) Math.sin((AnimationTickHolder.getTicks() + partialTicks) / 6);
hoverEndColor = ColorHelper.applyAlpha(0x70ffffff, flashValue);
hoverStartColor = ColorHelper.applyAlpha(0x30ffffff, flashValue);
}
else {
hoverIndex = -1;
hoverEndColor = 0;
hoverStartColor = 0;
}
hoverEndColor = ColorHelper.applyAlpha(0x70ffffff, flashValue);
hoverStartColor = ColorHelper.applyAlpha(0x30ffffff, flashValue);
} else {
hoverIndex = -1;
hoverEndColor = 0;
hoverStartColor = 0;
}
IntegerList keyframeTimes = activeScene.keyframeTimes;
for (int i = 0; i < keyframeTimes.size(); i++) {
int keyframeTime = keyframeTimes.get(i);
IntegerList keyframeTimes = activeScene.keyframeTimes;
for (int i = 0; i < keyframeTimes.size(); i++) {
int keyframeTime = keyframeTimes.get(i);
int keyframePos = (int) (((float) keyframeTime) / ((float) activeScene.totalTime) * (width + 4));
int startColor = i == hoverIndex ? hoverStartColor : 0x60ffeedd;
int endColor = i == hoverIndex ? hoverEndColor : 0x60ffeedd;
int startColor = i == hoverIndex ? hoverStartColor : 0x30ffeedd;
int endColor = i == hoverIndex ? hoverEndColor : 0x60ffeedd;
int height = i == hoverIndex ? 8 : 4;
int keyframePos = (int) (((float) keyframeTime) / ((float) activeScene.totalTime) * (width + 4));
GuiUtils.drawGradientRect(500, keyframePos, 1, keyframePos + 1, 4, startColor, endColor);
}
}
if (i == hoverIndex) {
FontRenderer font = Minecraft.getInstance().fontRenderer;
GuiUtils.drawGradientRect(500, keyframePos, 10, keyframePos + 1, 10 + height, endColor, startColor);
RenderSystem.pushMatrix();
RenderSystem.translated(0, 0, 400);
String text;
int offset;
if (activeScene.currentTime < keyframeTime) {
text = ">";
offset = -1 - font.getStringWidth(text);
} else {
text = "<";
offset = 3;
}
font.drawString(text, keyframePos + offset, 10, endColor);
RenderSystem.popMatrix();
}
GuiUtils.drawGradientRect(500, keyframePos, -1, keyframePos + 1, 2 + height, startColor, endColor);
}
}
@Override
public void playDownSound(SoundHandler handler) {
@Override
public void playDownSound(SoundHandler handler) {
}
}
}

View file

@ -13,7 +13,6 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import com.simibubi.create.foundation.ponder.instructions.KeyframeInstruction;
import org.antlr.v4.runtime.misc.IntegerList;
import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableObject;
@ -271,6 +270,8 @@ public class PonderScene {
instruction.tick(this);
if (instruction.isComplete()) {
iterator.remove();
if (instruction.isBlocking())
break;
continue;
}
if (instruction.isBlocking())
@ -299,10 +300,9 @@ public class PonderScene {
stoppedCounting = true;
}
public void markKeyframe() {
if (!stoppedCounting) {
keyframeTimes.add(totalTime);
}
public void markKeyframe(int offset) {
if (!stoppedCounting)
keyframeTimes.add(totalTime + offset);
}
public void addElement(PonderElement e) {

View file

@ -68,6 +68,7 @@ public class PonderUI extends AbstractSimiScreen {
private PonderButton left, right, scan, chap, userMode;
private PonderProgressBar progressBar;
private int skipCooling = 0;
public static PonderUI of(ResourceLocation id) {
return new PonderUI(PonderRegistry.compile(id));
@ -200,6 +201,9 @@ public class PonderUI extends AbstractSimiScreen {
public void tick() {
super.tick();
if (skipCooling > 0)
skipCooling--;
if (referredToByTag != null) {
for (int i = 0; i < scenes.size(); i++) {
PonderScene ponderScene = scenes.get(i);
@ -222,7 +226,8 @@ public class PonderUI extends AbstractSimiScreen {
PonderScene activeScene = scenes.get(index);
if (!identifyMode) {
ponderTicks++;
activeScene.tick();
if (skipCooling == 0)
activeScene.tick();
}
lazyIndex.tickChaser();
fadeIn.tickChaser();
@ -247,6 +252,8 @@ public class PonderUI extends AbstractSimiScreen {
replay();
getActiveScene().seekToTime(time);
if (time != 0)
coolDownAfterSkip();
}
public void updateIdentifiedItem(PonderScene activeScene) {
@ -312,7 +319,8 @@ public class PonderUI extends AbstractSimiScreen {
@Override
protected void renderWindow(int mouseX, int mouseY, float partialTicks) {
RenderSystem.enableBlend();
renderVisibleScenes(mouseX, mouseY, identifyMode ? ponderPartialTicksPaused : partialTicks);
renderVisibleScenes(mouseX, mouseY,
skipCooling > 0 ? 0 : identifyMode ? ponderPartialTicksPaused : partialTicks);
renderWidgets(mouseX, mouseY, identifyMode ? ponderPartialTicksPaused : partialTicks);
}
@ -362,7 +370,7 @@ public class PonderUI extends AbstractSimiScreen {
for (int f = 0; f < 4; f++) {
RenderSystem.translated(story.basePlateSize, 0, 0);
RenderSystem.pushMatrix();
RenderSystem.translated(0, 0, 1/1024f);
RenderSystem.translated(0, 0, 1 / 1024f);
GuiUtils.drawGradientRect(0, 0, 0, -story.basePlateSize, 4, 0x66_000000, 0x00_000000);
RenderSystem.popMatrix();
RenderSystem.rotatef(-90, 0, 1, 0);
@ -480,7 +488,7 @@ public class PonderUI extends AbstractSimiScreen {
}
if (identifyMode) {
if (noWidgetsHovered) {
if (noWidgetsHovered && mouseY < height - 80) {
RenderSystem.pushMatrix();
RenderSystem.translated(mouseX, mouseY, 100);
if (hoveredTooltipItem.isEmpty()) {
@ -518,11 +526,12 @@ public class PonderUI extends AbstractSimiScreen {
{
// Scene overlay
float scenePT = skipCooling > 0 ? 0 : partialTicks;
RenderSystem.pushMatrix();
RenderSystem.translated(0, 0, 100);
renderOverlay(index, partialTicks);
renderOverlay(index, scenePT);
if (indexDiff > 1 / 512f)
renderOverlay(lazyIndexValue < index ? index - 1 : index + 1, partialTicks);
renderOverlay(lazyIndexValue < index ? index - 1 : index + 1, scenePT);
RenderSystem.popMatrix();
}
@ -841,4 +850,8 @@ public class PonderUI extends AbstractSimiScreen {
return true;
}
public void coolDownAfterSkip() {
skipCooling = 15;
}
}

View file

@ -203,6 +203,22 @@ public class SceneBuilder {
addInstruction(new RotateSceneInstruction(0, degrees, true));
}
/**
* Adds a Key Frame at the end of the last delay() instruction for the users to
* skip to
*/
public void addKeyframe() {
addInstruction(KeyframeInstruction.IMMEDIATE);
}
/**
* Adds a Key Frame a couple ticks after the last delay() instruction for the
* users to skip to
*/
public void addLazyKeyframe() {
addInstruction(KeyframeInstruction.DELAYED);
}
public class EffectInstructions {
public void emitParticles(Vec3d location, Emitter emitter, float amountPerCycle, int cycles) {
@ -349,10 +365,6 @@ public class SceneBuilder {
addInstruction(AnimateParrotInstruction.move(link, offset, duration));
}
public void addKeyframe() {
addInstruction(KeyframeInstruction.INSTANCE);
}
}
public class WorldInstructions {

View file

@ -27,7 +27,7 @@ public class GantryScenes {
String id = "gantry_" + (pinion ? "carriage" : "shaft");
String title = "Using Gantry " + (pinion ? "Carriages" : "Shafts");
scene.title(id, title);
scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -2 * f);
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
@ -46,10 +46,9 @@ public class GantryScenes {
: "Gantry Shafts form the basis of a gantry setup. Attached Carriages will move along them.";
scene.overlay.showText(80)
.attachKeyFrame()
.text(text)
.pointAt(util.vector.centerOf(centralShaft));
scene.special.addKeyframe();
scene.idle(80);
scene.world.hideIndependentSection(gantry, Direction.UP);
@ -58,10 +57,10 @@ public class GantryScenes {
Vec3d gantryTop = util.vector.topOf(4, 2, 2);
scene.world.modifyKineticSpeed(util.select.everywhere(), f -> 0f);
scene.overlay.showText(40)
.attachKeyFrame()
.text("Gantry setups can move attached Blocks.")
.pointAt(gantryTop)
.placeNearTarget();
scene.special.addKeyframe();
scene.idle(30);
Selection planks = util.select.position(5, 3, 1);
@ -75,12 +74,11 @@ public class GantryScenes {
scene.idle(20);
scene.overlay.showText(80)
.attachKeyFrame()
.sharedText("movement_anchors")
.pointAt(gantryTop)
.placeNearTarget();
scene.special.addKeyframe();
scene.idle(80);
scene.special.addKeyframe();
scene.world.modifyKineticSpeed(util.select.layer(0), f -> 32f);
scene.world.modifyKineticSpeed(util.select.layer(1), f -> -64f);
@ -122,12 +120,12 @@ public class GantryScenes {
BlockPos cogPos = util.grid.at(1, 2, 1);
scene.overlay.showText(60)
.attachKeyFrame()
.colored(PonderPalette.RED)
.pointAt(util.vector.centerOf(cogPos.down()
.south()))
.text("Redstone-powered gantry shafts stop moving their carriages")
.placeNearTarget();
scene.special.addKeyframe();
scene.idle(70);
Selection cogSelection = util.select.position(cogPos);
@ -171,10 +169,10 @@ public class GantryScenes {
scene.world.moveSection(gantry2, util.vector.of(-1, 0, 0), 20);
scene.overlay.showText(80)
.attachKeyFrame()
.text("The movement direction of carriages depend on their shafts' orientation")
.pointAt(util.vector.topOf(1, 1, 3))
.placeNearTarget();
scene.special.addKeyframe();
scene.idle(80);
BlockPos lastShaft = util.grid.at(0, 1, 2);
@ -192,10 +190,10 @@ public class GantryScenes {
if (i == 0) {
scene.overlay.showText(80)
.attachKeyFrame()
.text("...as well as the rotation direction of the shaft")
.pointAt(util.vector.blockSurface(lastShaft, Direction.WEST))
.placeNearTarget();
scene.special.addKeyframe();
}
scene.idle(30);
@ -221,10 +219,10 @@ public class GantryScenes {
scene.idle(20);
scene.overlay.showText(120)
.attachKeyFrame()
.text("Same rules apply for the propagated rotation")
.pointAt(util.vector.topOf(0, 3, 3))
.placeNearTarget();
scene.special.addKeyframe();
scene.idle(20);
for (boolean flip2 : Iterate.trueAndFalse) {
@ -268,9 +266,9 @@ public class GantryScenes {
scene.world.moveSection(gantry, util.vector.of(0, 2, 0), 40);
scene.overlay.showText(60)
.attachKeyFrame()
.text("Gantry shafts attach to a carriage without the need of super glue")
.independent(20);
scene.special.addKeyframe();
scene.idle(40);
scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f);
@ -281,9 +279,9 @@ public class GantryScenes {
scene.world.showIndependentSection(util.select.position(gantryPos2), Direction.DOWN);
scene.idle(15);
scene.overlay.showText(60)
.attachKeyFrame()
.text("Same applies for carriages on moved Gantry Shafts")
.independent(20);
scene.special.addKeyframe();
scene.idle(15);
scene.world.moveSection(gantry, util.vector.of(0, 2, 0), 40);

View file

@ -71,6 +71,11 @@ public class TextWindowElement extends AnimatedOverlayElement {
return this;
}
public Builder attachKeyFrame() {
scene.builder().addLazyKeyframe();
return this;
}
}
@Override

View file

@ -5,9 +5,14 @@ import com.simibubi.create.foundation.ponder.PonderScene;
public class KeyframeInstruction extends PonderInstruction {
public static final KeyframeInstruction INSTANCE = new KeyframeInstruction();
public static final KeyframeInstruction IMMEDIATE = new KeyframeInstruction(false);
public static final KeyframeInstruction DELAYED = new KeyframeInstruction(true);
private boolean delayed;
private KeyframeInstruction() { }
private KeyframeInstruction(boolean delayed) {
this.delayed = delayed;
}
@Override
public boolean isComplete() {
@ -19,6 +24,6 @@ public class KeyframeInstruction extends PonderInstruction {
@Override
public void onScheduled(PonderScene scene) {
scene.markKeyframe();
scene.markKeyframe(delayed ? 6 : 0);
}
}