CrashNet Server 2.0.2 Release Notes

Crash BASIC 2.0.2 Release Notes

~written by Crash-tan~

A shader one! Transitions you write yourself finally move, SCREEN counts the same pixels as SCREEN_SIZE, USE COLOR works, and a shader with a mistake in it stops and tells you what the mistake is, instead of quietly drawing something else.

Not only shaders, though: blue that drew red, text that was always white on Windows, videos with their reds and blues swapped, maps and layers that didn’t reach the edges with LETTERBOX OFF, and a JavaScript timer that ticked once after it was stopped are all put right too. And there’s UUID, a name nothing else will ever have.

YOUR OWN TRANSITIONS MOVE

CLS !! effect_shader("name") clears a layer with a transition you wrote: a shader with a USE NUMBER progress setting, which I take from 0 to 1. Except I didn’t. The layer sat there unchanged for the whole transition, and then cleared all at once.

A shader’s settings are named in capitals once I’ve read them, so yours was PROGRESS, and I was setting progress. The names never matched, and progress stayed at its DEFAULT. The same went for target_r, target_g, target_b and target_a, the color the layer is clearing to.

Now a setting’s name matches whatever case it’s written in, everywhere I set one, so your transition runs from start to finish:

SHADER "curtain"
  USE NUMBER progress DEFAULT 0
  WHEN DRAWING
    c = IMAGE
    closed = STEP(1.0 - progress, ABS(UV.x - 0.5) * 2.0)
    SET COLOR = MIX(c, RGB(0.5, 0.0, 0.1), closed)
  END WHEN
END SHADER

CLS EFFECT("curtain")
CLS 0 !! effect_shader("curtain")

SCREEN COUNTS THE GAME’S PIXELS

SCREEN in a shader is where the pixel is on the screen. It counted the window’s pixels, though, while SCREEN_SIZE counts the game’s. In a window the game’s size, they agree. In a window twice as big, SCREEN went up to twice SCREEN_SIZE, so SCREEN / SCREEN_SIZE reached 1 halfway across, and screen-space effects like scanlines came out a different size in every window. A letterbox’s black bars were counted too, so the top left of your game wasn’t (0, 0).

Now SCREEN is in the game’s pixels, the same ones SCREEN_SIZE counts, from (0, 0) at the top left of the game. On a 320x240 game it runs from 0 to 320 across, however big the window is, on desktop, phones, TVs and the web:

SHADER "dusk"
  WHEN DRAWING
    down = SCREEN.y / SCREEN_SIZE.y
    SET COLOR = MIX(IMAGE, RGB(0.9, 0.4, 0.1), down * 0.6)
  END WHEN
END SHADER

If you divided SCREEN by the window’s scale yourself to make up for it, take that out.

USE COLOR WORKS

USE COLOR declares a color setting, and it was broken three ways. Its DEFAULT was never used, so it always started as nothing at all. It was put in the wrong place, overlapping the setting before it. And there was no way to give it a color from your program.

Now it works. Its DEFAULT is RGB(r, g, b) or RGBA(r, g, b, a), and without one it’s opaque black. From your program, give it three numbers from 0 to 1, red, green and blue, or four with the alpha, as a coordinate or a list:

SHADER "tint"
  USE COLOR tint DEFAULT RGB(1.0, 1.0, 1.0)
  WHEN DRAWING
    c = IMAGE
    SET COLOR = RGBA(c.r * tint.r, c.g * tint.g, c.b * tint.b, c.a)
  END WHEN
END SHADER

SET SPRITE 1 SHADER "tint", @tint=(1.0, 0.4, 0.4)
SET SPRITE 1 !! shader("tint") shader_params({tint: (1.0, 0.4, 0.4)})
SET LAYER 0 !! shader("tint") shader_params({tint: [0.4, 0.4, 1.0, 0.5]})

With three numbers, the alpha is 1. In Python, it’s a tuple or a list: shader_params={"tint": (1.0, 0.4, 0.4)}. A color takes four of the 64 numbers a shader’s settings have room for.

SHADER MISTAKES STOP AND SAY SO

A lot of shader mistakes used to do something, just not what you meant. Now each one stops your program, says what was wrong, and says what would be right.

When I build the shader:

When you put a shader on something:

CLEARER WORDS FOR TWO SHADER LINES

Two things a shader can’t have used to get my most puzzled error, “I got confused by the syntax here”. Now they get their own:

CLEARER WORDS FOR A SQL BLOCK

A NULLS value or a USE line’s DEFAULT can’t be negative either. NULLS seconds = -1 wasn’t read as a NULLS line at all, so it went to the database as part of the SQL, and the database said “near”NULLS”: syntax error” the first time you ran it. The same went for any USE or NULLS line I couldn’t read.

Now I stop at the block itself, show you the line, and say what’s wrong with it. For a negative one, I suggest a value of 0 or more, or letting the SQL choose it: SELECT COALESCE(seconds, -1) AS seconds.

WHEN THE GRAPHICS CHIP SAYS NO

Some shader mistakes only the graphics chip can find, nearly always values of different sizes in one sum or function: a color plus a place, or MIN of a color and a number. When it refused one, I added “This may be a bug in the shader compiler. Please report this issue.”, even when the mistake was in the shader.

Now I say what that kind of refusal usually means, in the shader language’s words: values of different sizes in a function or a sum, a swizzle of a part that isn’t there (UV.z), or SET COLOR given fewer than four parts. The chip’s own message comes with it, and it’s now the whole message, with the line it points at, rather than just “Entry point fs_main at Fragment is invalid”.

BLUE IS BLUE AGAIN

On a lot of computers, Macs among them, the graphics chip keeps a picture’s colors blue first. Some of what I put into a picture went in red first, so red and blue swapped places:

SCREEN 320, 240
MEMORYBUFFER "rings", 64, 64
    CIRCLE (32, 32), 31, 1
END MEMORYBUFFER
SET IMAGE "rings"
CIRCLE (32, 32), 20, 1
SET LAYER 0
PUTIMAGE (0, 0), "rings"

Now both rings are blue. The same went for the colors you give with SET PALETTE OFF, and they’re right now too.

TEXT IN COLOR ON WINDOWS

On Windows, everything you PRINTed came out white, whatever COLOR said. The background color worked, so COLOR 7, 4 gave you white words on red instead of grey ones. I keep my letters white and paint them as I draw them, and on Windows I forgot the paint.

Now text is the color you asked for, on Windows like everywhere else:

SCREEN 640, 480
PRINT "Hello World"
COLOR 4
PRINT "Hello World"
COLOR 7, 4
PRINT "Hello World"

VIDEOS IN THE RIGHT COLORS

A video’s frames come from a different place on every kind of computer, and some of them come blue first while others come red first. I took them all to be blue first, so on Android, and in the web player, a video’s reds and blues were swapped: a red car drove by blue.

Now every frame says which way round it is, and I put it up the right way.

UUID

UUID gives you a name nothing else will ever have: 36 characters, like 3f2b8c1e-9d4a-4e7b-a6c5-1b2d3e4f5a6b, and a new one every time you read it. It’s handy for naming something that mustn’t clash with anything else, like a save slot or a player’s record:

id$ = UUID
PRINT "Save slot: "; id$
SCREEN 320, 240
slot = uuid
PRINT "Save slot", slot

It comes from the computer’s own randomness, not from RND, so RANDOMIZE doesn’t make it repeat. In Python, JavaScript and Lua, it’s crash.uuid.

LETTERBOX OFF GOES EDGE TO EDGE

With LETTERBOX OFF, your game’s screen sits on the same pixels it always does, and the rest of the window is yours to draw on too. A map stopped at the edge of the screen, though, even when there was more of it, and the window beside it stayed black. And three kinds of layer did reach the edges of the window, but stretched to its shape, so in a wide one a circle came out an egg:

SCREEN 320, 240 !! letterbox(FALSE)
CREATE LAYER 1, 320, 240
SET LAYER 1
CIRCLE (160, 120), 80, 14
SET LAYER 1 !! plane("affine") zoom(1) wrap_x wrap_y
SET SCROLL 160, 120 !! angle(0)

Now all of them go edge to edge, the right shape: a map carries on past your screen as far as it goes, a plane goes on to the window’s edges, and a wrapped layer tiles across the whole window. What’s on your screen doesn’t move. A map or a wrapped layer with a SHADER of its own still stops at the edge of the screen for now, the right shape.

JAVASCRIPT CALLBACKS RUN TO THE END

In JavaScript, a timer, an event or a render callback that came while your program was waiting on an await could stop part-way, and the rest of your program ran in the middle of it. So clearInterval could return, and the interval still tick once more afterwards, about one time in fifteen:

let ticks = 0;
const ticking = setInterval(() => { ticks += 1; }, 5);
while (ticks < 2) await crash.yield();
clearInterval(ticking);
const stopped_at = ticks;
await crash.delay(40);
console.log(ticks === stopped_at);  // sometimes false!

Now a callback runs to the end before your program carries on, the way JavaScript always promises, and that’s true every time.

SHADER AND SQL BLOCKS IN COLOR

What’s inside a SHADER or SQL block isn’t BASIC, so the editor used to color all of it like one long string. Now it’s colored as what it is, in the IDE, in the book and anywhere else I color code.

In a shader, USE, DEFAULT, WHEN DRAWING and SET COLOR are keywords, and MIX, RGB, UV, IMAGE and the rest of what a shader gives you are built-ins. In a SQL block, the USE and NULLS lines are colored like BASIC, and the statement after them like SQL: SELECT and WHERE are keywords, 'it''s' is a string, -- like this is a comment, and @least is your parameter.

That fixes one thing in Crash BASIC 1 as well. There, a ' in a SQL block started a BASIC comment, so a string like 'it''s' was colored as a comment right to the end of the line.

THE HELP AND THE BOOKS KEEP UP

The help for SHADER used to say what a shader can do only in Crash BASIC 1. Now the help in Crash BASIC 2, Python, JavaScript and Lua says it too: what USE NUMBER, USE COLOR and USE IMAGE take, that a DEFAULT can’t be negative, what SCREEN counts, and which mistakes stop your program. The help for SQL says the same about a NULLS value, in both Crash BASICs.

Every example in the help, in every language, now shows what it does when you try it. Some never opened a screen, so what they printed went nowhere; some made a sprite and never showed it; and some printed underneath a map, which covered the words up. And they all use the same pictures, sounds and maps as the books now: me running, the courtyard, a real explosion, rather than a couple of colored squares.

A few CIRCLE examples gave TRUE where the fill color goes. The fill is a color, so in palette mode that filled the circle blue, whatever its outline was, and with SET PALETTE OFF it was a fill you couldn’t see. They all give a real color now.

There’s a new book, Shaders with Crash, all about writing your own shaders. Its cookbook has a recipe for a glow, where the bright parts of the picture shine onto the dark around them. Making Games with Crash has a new chapter, Databases, about keeping scores, saves and shops in a database: what CLOSE does, where a database is kept, changing what’s in one, and NULLS. And its chapter on layers now shows sprites standing on a floor that goes off into the distance, and jumping off it.

In the books, an example with a mistake in it on purpose now says so above it, and the very next one is the same example put right, so you can run into the mistake and then into the fix. A page opens on its first example that works, instead of greeting you with an error.

All the books are in one place now too, the Crash Library: Learn Crash BASIC, Making Games with Crash, Shaders with Crash, and the Crash BASIC 2 reference, as a book of its own where every example runs with Try it.

A CORRECTION: PX

The shader cookbook said PX(x, y) divides by the screen’s size, so that a shader couldn’t count its own picture’s pixels without being told how big it is. That was wrong. PX counts the pixels of the picture the shader is drawing: the sprite’s current frame, or the layer. So OWNTEXTURE(UV + PX(1.0, 0.0)) is always the next pixel to the right, however big the sprite is and however far it’s scaled. Only a USE IMAGE picture’s size has to be passed in. The cookbook’s scrolling recipe uses PX now, and doesn’t need its picture’s height any more.