Skip to content

Instantly share code, notes, and snippets.

@ubuntor
Created November 30, 2022 07:40
Show Gist options
  • Save ubuntor/8abbec2162a6da31581756edd144111b to your computer and use it in GitHub Desktop.
Save ubuntor/8abbec2162a6da31581756edd144111b to your computer and use it in GitHub Desktop.
int frame = 0;
int depth_limit = 9;
int ti = -1;
String world = "";
String world_ending = "...";
int world_length = 3;
PVector main = new PVector(400, 400, 90);
PVector ba;
PVector bb;
PVector bc;
PVector p;
PImage stage1;
PImage stage2;
int movetime = 240;
float colorscale = 0.9;
// x,y,s vectors
PVector atargets[] = {
new PVector(400, 400, 30),
new PVector(400-30, 400, 30),
new PVector(400-90*1, 400, 90)
};
PVector btargets[] = {
new PVector(400, 400+30, 30),
new PVector(400, 400+30, 30),
new PVector(400, 400+30, 30)
};
PVector ctargets[] = {
new PVector(400-10, 400+30, 10),
new PVector(400-10, 400+30, 10),
new PVector(400-30, 400+30, 30)
};
PVector ptargets[] = {
new PVector(400+30, 400, 30),
new PVector(400, 400, 30),
new PVector(400-30, 400, 30)
};
void setup() {
rectMode(CENTER);
ellipseMode(CENTER);
size(800, 800);
stage1 = loadImage("stage_1.png");
stage2 = loadImage("stage_2.png");
frameRate(60);
}
boolean approx_equal(float x, float y) {
return abs(x-y) < 0.01;
}
void clipped_rect(float x, float y, float s) {
if (x + s/2 <= 0 || x - s/2 >= 800 || y + s/2 <= 0 || y - s/2 >= 800) {
return;
}
rect(x, y, s, s);
}
void draw_box(float x, float y, float s, float colorscale, String label, int depth, boolean cloned) {
boolean is_main = approx_equal(x, main.x) && approx_equal(y, main.y) && approx_equal(s, main.z);
if (is_main) {
stroke(255, 255, 255);
} else {
stroke(0, 0, 0);
}
if (s >= 2) {
fill(80*colorscale, 100*colorscale, 200*colorscale);
clipped_rect(x, y, s);
textAlign(CENTER, CENTER);
textSize(s);
fill(255, 255, 255, 128);
text(label, x, y - textAscent()*0.08);
fill(100*colorscale, 160*colorscale, 250*colorscale);
clipped_rect(x+s/3, y+s/3, s/3);
}
float ratio = s/main.z;
PVector ad = PVector.sub(ba, main);
PVector bd = PVector.sub(bb, main);
PVector cd = PVector.sub(bc, main);
PVector pd = PVector.sub(p, main);
draw_player(x + ratio*pd.x, y + ratio*pd.y, ratio*p.z, colorscale);
if (depth > 0) {
if (!cloned) {
draw_box(x + ratio*ad.x, y + ratio*ad.y, ratio*ba.z, colorscale + 0.1, "A", depth-1, cloned);
draw_box(x + ratio*bd.x, y + ratio*bd.y, ratio*bb.z, colorscale + 0.1, "B", depth-1, cloned);
} else {
if (label.equals("A")) {
draw_box(x + ratio*ad.x, y + ratio*ad.y, ratio*ba.z, colorscale + 0.1, "A", depth-1, cloned);
draw_box(x + ratio*bd.x, y + ratio*bd.y, ratio*bb.z, colorscale + 0.1, "B", depth-1, cloned);
draw_box(x + ratio*cd.x, y + ratio*cd.y, ratio*bc.z, colorscale + 0.1, "C", depth-1, cloned);
} else {
draw_box(x + ratio*bd.x, y + ratio*bd.y, ratio*bb.z, colorscale + 0.1, "B", depth-1, cloned);
draw_box(x + ratio*cd.x, y + ratio*cd.y, ratio*bc.z, colorscale + 0.1, "C", depth-1, cloned);
}
}
}
}
void draw_player(float x, float y, float s, float colorscale) {
stroke(0, 0, 0);
fill(242*colorscale, 134*colorscale, 228*colorscale);
clipped_rect(x, y, s);
fill(10*colorscale, 10*colorscale, 10*colorscale);
ellipse(x-2.8*s/10, y-0.8*s/10, s/5, s/5);
ellipse(x+2.8*s/10, y-0.8*s/10, s/5, s/5);
}
PVector interp(PVector a, PVector b, float t) {
return PVector.add(PVector.mult(a, 1-t), PVector.mult(b, t));
}
void draw() {
boolean cloned = frame >= movetime*3;
if (frame % (movetime*2) == 0) {
ti += 1;
if (ti == atargets.length) {
println("done");
noLoop();
return;
}
}
if (frame % (movetime/2) == 0) {
String new_world = world;
while (new_world.equals(world)) {
new_world = "";
if (cloned) {
world_ending = "...";
for (int i = 0; i < world_length; i++) {
int r = (int)(random(8));
if (r < 2) {
new_world += "A";
world_ending = "∞";
break;
} else if (r < 5) {
new_world += "B";
} else if (r < 8) {
new_world += "C";
}
}
} else {
for (int i = 0; i < world_length; i++) {
if ((int)(random(2)) == 0) {
new_world += "A";
} else {
new_world += "B";
}
}
}
}
println(Integer.toString(frame)+" "+new_world);
world = new_world;
}
if (frame % (movetime*2) >= movetime && ti < atargets.length-1) {
float t = ((float)(frame % (movetime*2) - movetime))/movetime;
ba = interp(atargets[ti], atargets[ti+1], t);
bb = interp(btargets[ti], btargets[ti+1], t);
bc = interp(ctargets[ti], ctargets[ti+1], t);
p = interp(ptargets[ti], ptargets[ti+1], t);
} else {
ba = atargets[ti];
bb = btargets[ti];
bc = ctargets[ti];
p = ptargets[ti];
}
background(0);
float outerx = main.x;
float outery = main.y;
float outers = main.z;
float cs = colorscale;
for (int i = 0; i < world.length(); i++) {
PVector parent;
switch (world.charAt(i)) {
case 'A':
default:
parent = ba;
break;
case 'B':
parent = bb;
break;
case 'C':
parent = bc;
break;
}
PVector d = PVector.sub(main, parent);
outerx += outers/parent.z * d.x;
outery += outers/parent.z * d.y;
outers *= main.z/parent.z;
}
if (world.charAt(world.length()-1) == 'A' && cloned) {
for (int i = 0; i < world_length - world.length() + 2; i++) {
PVector d = PVector.sub(main, ba);
outerx += outers/ba.z * d.x;
outery += outers/ba.z * d.y;
outers *= main.z/ba.z;
cs *= colorscale;
}
}
draw_box(outerx, outery, outers, cs, world.substring(world.length()-1), depth_limit, cloned);
textSize(36);
textAlign(LEFT);
fill(255, 255, 255, 255);
text("World: "+world+world_ending, 500, 750);
if (cloned) {
image(stage2, 50, 508);
} else {
image(stage1, 50, 525);
}
saveFrame("/tmp/parabox-######.tga");
frame += 1;
}
@ubuntor
Copy link
Author

ubuntor commented Dec 1, 2022

stage_1.png: stage_1
stage_2.png: stage_2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment