SCRMaps
/
Sign in

Precomputing the whole thing at compile time

Instead of computing a coordinate each frame, compute every frame at build time and leave the map a jump table.

13 min read

The previous lesson computed at the moment of the cast. You can go one step further and compute before the game starts at all, while the map is being built. epScript's foreach(t : py_range(...)) is not a runtime loop - it is a Python loop that unrolls at compile time, so whatever you write inside it becomes that many copies of a trigger.

// 나선형 권적 한 바퀴 / one revolution of a log spiral
const PERIOD = 120;

EUDSwitch(tick) {
    foreach(t : py_range(PERIOD)) {
        EUDSwitchCase(t);
        const dx, dy = SPIRAL[t];           // 파이썬으로 미리 계산한 값
        if (dx != 0) addlocx(loc, dx * 2);  // 한 변을 2d만큼 / one edge by 2d
        if (dy != 0) addlocy(loc, dy * 2);
        CreateUnit(1, EFFECT, loc, P1);
        EUDBreak();
    }
}
SPIRAL is filled by Python while the map is built. Not one line of arithmetic survives into the map.
Three things in that snippet
Move one edge by 2d, not two by dCreateUnit spawns at the centre of a location. To move the centre by d you can move both edges by d - or move ONE edge by 2d, which moves the centre by exactly the same d for half the actions.
Skip an axis that does not changeSort the points and emit only the non-zero deltas. Over a revolution that removes a visible fraction of the actions.
n-fold symmetry means 1/n of the workA five-petal figure needs only a fifth of a revolution precomputed and then repeated five times. The interior angle of a regular n-gon is 90*(n-2)/n.

To make an effect unit a point, set unitBoundsLT = 0 and unitBoundsRB = 65537. Both then name the same single pixel, so the collision box disappears and stacked copies do not push each other.

It is not free. Compile-time computation really does emit the triggers, so the map file grows - one 120-frame revolution becomes hundreds of triggers. And what is written in advance cannot react to anything. It is stiffer even than the queue in the previous lesson.

Cleanup is the fragile part. The effects are created through CUnit.from_next() and have to be reaped later, and because this creates several in one frame it is easy to lose track of “the one just made”. Put them in a UnitGroup as they are created rather than walking from_next() afterwards.

So there are three ways to build an animation. Per cycle: it can react, and it is the most flexible. Planned at cast time: a many-stage animation becomes data. Unrolled at compile time: almost no runtime cost, at the price of map size and of not reacting at all. Choose on two questions - does it have to react, and how often does it run.

Queue, Plan, ExecCode that runs at compile time
Sign in to track your progress