This is how we were exploring the marvels of programming and mathematics back in the days. I had lot of fun and knowledge from this kind of experiments. I miss the '80
The Super Expander defined my Vic-20 experience as a child. Every game I wrote in Basic took full advantage of the extra 3K of RAM. And I tinkered with its graphic tricks a time or two, though not in any game-related capacity. Half of the programs I wrote were really just musical tunes, and that 3K let me write things that lasted three minutes instead of two. But even at the time, as a very young kid, I could definitely tell that I was beating my head against some really quite unreasonable limitations. Not just the threat of running out of RAM but also the fact that you couldn't feasibly write a game in Basic and get better than about 4fps out of it. And I remember typing in those programs from the manual. I remember typing in that one approaching-asteroid game on like five different occasions, and only on the fifth did I manage to do so without catastrophic typoes that rendered zero result. I remember the day that I understood the whole point of looping to achieve motion (I guess I never bothered to try reading or understanding the provided explanation). Eh, what can I say, it was a big deal at that age.
Man this made me realize I still have a lot to learn math wise, basic wise, and commodore wise 😅. But thank you for this! I'll see how much I can understand!
Simpler to just use DX=DX * (DX>0) * (DX < 90) * (-(DX =0)) * (-(DX=89)) - this will leave dx alone if it is 1 - 88 but flip it from -1 to +1 or +1 to -1 if it is equal to 0 or 89 - ie reversing direction. YOu would do the same for DY. This assumes Basic gives you a 1 for true, 0 for false. This is how I would implement it Smart BASIC for the coleco adam
C= BASIC gives a -1 for true, and 0 for false, so you'd have to adjust accordingly. Mine was DX=DX*(1+((x=w or x=0)*2)) I can tell you were reasoning the same way I was. Nicely done.
I got a used Commodore VIC-20 in storage... ah... I grew up on this as a kid in the 1980s... great intro to computers.. had to type in all the programs from magazines and save to tape, and then finally to disk... those were the days...
Yeah, Miss those days too, I now just have emulators, but still looking for sites, where I can get those old magazines so I could type in my lonely nights :)
@@kentskjnnemann5629 Yup. I spent hours and hours as a kid typing in basic and ML programs from magazines and then saving them onto unreliable Datasette and hope they dont get lost or it's wasted hours of typing time.. the fun.. and troubleshooting if you mistype the program.. ugh.. heheh.. good old days.
It’s interesting finding a few videos about the Super Expander here. I thought I was the only one who bought one. :) I used mine for doing TV graphics for videos that my father made. It was fun seeing my VIC-20 titles running at a booth at the Houston Boat Show. I look forward to getting a TheC64 if they become available in the US just for playing VIC stuff with a real VIC keyboard.
5:00 I prefer to code more defensively and use conditions like “IF X = W”. This way, even if something goes wrong, your program doesn't take off to never-never land. 6:27 If instead of “S=11.38”, you put “S=1024/90” into your program, it would both make it more clear what the value means and make the value more precise. The execution time doesn't matter since the statement is only executed once. Also, to make your plot touch the right edge of the screen (it doesn't), you want to map the program coordinate 89 to screen coordinate 1023, so the expression would be “S=1023/89”. It's like when people map color values from 8 bits to 16 bits by multiplying by 256. That's wrong; they need to multiply by 257 (65535/255) to get the proper mapping of $FF to $FFFF. 8:34 I seem to recall that the Super Expander uses floating-point arithmetic to draw lines rather than an integer method like Bresenham's algorithm. This would make it slow and probably more jagged, especially if they don't start plotting from "pixel centers". 8:50 The obvious way to replace IF/THEN statements is to use numeric results from comparisons like you did in the adventure game. You don't need to jump to parametric equations unless you're disallowed to use comparisons. 60 DX=DX-2*(X=W) Or, more defensively: 60 DX=-DX*(X>0 AND X
Coming back to this one again, this might be your most underrated video. Your approach to the repeating pattern has so many applications that are worth study and experimentation.
Awesome work and fantastic explanation, as usual. It's fun to see the Super Expander cart in action. I very much enjoyed these VIC-20 episodes. Thanks for the great videos!
woooooooow! geez just watching you work makes me think programming basic on a commodore is the coolest thing ever! just using the screen as a notepad and calculator and just replacing variable names and then giving it a unique line number to get both versions into the program. woooooooow. there's a lot to like about this workflow!
It felt like a step backward when I went to the Amiga and MS-DOS systems and was stuck with a command line. Obviously those computers have abilities way beyond the 8-bit Commodore computers, but in this particular area they weren't as versatile and fun to use.
Great video. My family owned a VIC-20 when I was young but I never got to see anyone write, edit and debug a program on it. I paused the video halfway through to see if I could solve the problem. This is what I ended up with - it doesn't use abs(), but a multiplier and offset that are calculated from a toggle that takes advantage of integer division. I decided to use perl. for ($t = 0; ; $t++) { use integer; # gives % proper behaviour my $toggle = ($t % (2 * $w)) / $w; my $multiplier = ($toggle * -2) + 1; my $adder = $toggle * $w; my $x = $adder + $multiplier * ($t % $w); $toggle = ($t % (2 * $h)) / $h; $multiplier = ($toggle * -2) + 1; $adder = $toggle * $h; my $y = $adder + $multiplier * ($t % $h); $array[$x][$y] = 1; . . . }
I don't have a VIC-20, so I followed along on a 64 with Simon's Basic, just required a few minor changes. I love the way you approached the repeating pattern.
Thanks for this very well done video! Having studied CS, this showed me how seamlessly you can combine, let’s say, sketch and code mode in basic! Never thought of this that way! Cheers!
If love this I did a lot of programming from Museum interactions to new prison build security and maintenance solutions any larger machines of course but you tweeked my enthusiasm from my first time on my first program on vic 20 when a kid
Maths always gives me a headache but you described this very clearly. The x, y, dx and dy from the Vic 20 manual has stuck with me since I first discovered it at age eleven. Thanks for making this video, I will check out the others on the channel.
I was able to generate the display in BASIC using VICE without any memory or basic expansion. Used 1 IF statement to check for keypress to terminate loop but not for the plotting algorithm.
The points are still drawn correctly. It's the linear interpolation you introduced with the line command which draws the lines in the wrong places. If you put the plot command back and generate T value randomly, you will eventually draw the figure after some time.
however, since the function will eventually cover the whole screen, you'd need a limited T range to produce a recognizable pattern. Interesting that when he incremented T by 64, it came up with a starburst shape when he did that.
Or simulate a ternary if operator by multiplying with booleans that evaluate to True/False->-1/0; something like: FLIPX=(X=0)OR(X=W):DX=(FLIPX - NOT FLIPX)*DX Similar for Y. Haven't done Basic for ages, so apologies for errors, but you'll get the point...
I had so much fun with my VIC-20. Using HESMON I wrote many programs in machine code. The best was a crude windows 3 using a joystick and 1 floppy drive.
My first thought might be more intuitive: imagine unfolding the screen like a book. The real screen has a mirrored screen to the right. Now, the X position is simply a modulo. Now how to recover the mirrored image back to where it belongs: How far is the value from the fold line? Absolute value of the difference between X and real width. That is from the right, so subtract from the width. Do the same for the Y direction.
I paused it and came up with pretty much the same thing using an Atari emulator. though I didn't think of the offset, so my program started in the bottom right corner. I also used a medium-res bitmap mode so speed wasn't an issue. for yours, the initial test program could have been a little more entertaining if you'd changed this line: 30 PRINT T;TAB(10+X);X
I just did this with QBasic on DOSBox. The gist of my code: SCREEN 13 DEFINT A-Z FOR t = 0 TO 6952 mx = t MOD 178 my = t MOD 158 fx = mx \ 89 fy = my \ 79 x = (fx * (178 - mx)) + ((1 - fx) * my) y = (fy * (158 - my)) + ((1 - fy) * my) PSET (x, y), 15 NEXT (at t = 6952, the whole display is filled, so there's no point in continuing). This really needs the integer division operator \ as the / operator does rounding, which is not desired in this case.
Sorry if I'm wrong but I thought you said in that 10 line adventure game video that you couldn't have multiple statements on one line? So how does line 50 work? the OX=X : OY=Y one ...
@@suvetar It was on the ZX81 that you were limited to 1 statement per line. On Commodore Basic it was not an issue. He had to use multiple statements per line as the very unique but elegant string slicing functions* of Sinclair Basic did not exist on Microsoft derived Basics. * slicing has been "rediscovered" recently and is all the rage in modern programming languages like D or Rust, with lots of effort to introduce to C++, C# and Java.
Using a non-integer scaling factor on a 1-bit display (no possibility of anti-aliasing of any kind) always yields ugliness. You're /effectively/ rendering the lines at 90*80, then scaling it up to the VIC's native resolution with nearest-neighbor interpolation. Best practice (I think) is to use a whole number scaling factor (possibly whole number + 0.5) and just center the somewhat smaller output in the display.
You folks suggest CMP/BEQ are missing the point. a CMP BEQ *is* an if statement. It’s comparing a value and executing code based on its truth value. The challenge was to do this without any comparison opcodes.
Would adding a DEF FN for X or Y make any difference in the speed of the algorithm? 10:47 "Please excuse the crudity of this model. I didn't have time to build it to scale or paint it." - Doc Brown
Haven't used Vic 20's Basic but my method would have been filling arrays counting up and down using for loops for x and y then using POINTS 1, T MOD X(T), T MOD Y(T) at each time step.
No IF statements? CMP/BEQ let's go Also, you could have had the scalars automatically calculated and be able to do pretty much any resolution - Even ones much higher than are actually displayed for supreme accuracy!
Does the VIC's video chip 'see' the 3K RAM (when installed)? In the emulator it shows just noise. Is there a register to change to other 16K blocks just like the C64 or is the VIC (one) only connected to $0000-$1FFF and $8000-$9FFF ?
My initial thought was to just use a for/next loop (for x=0 to w, etc). I haven't actually tried to write it, but I can pretty quickly see the issue of being stuck in one loop at a time, or in other words only being able to adjust the x or y value. So unfortunately not as simple as I thought :)
Yes, as soon as you try to do two independent things at once, for/next loops become a lot less useful. I remember hitting that in my early days of game development, figuring out how to move a sprite across the screen with a for/next loop, feeling I had it all figured out, and then thinking "how do I move a second sprite independently?"
I should get a super expander for my Vic-20. It was NIB in 1996 when I stupidly unboxed it and have not used it since, except to test that it works. Some C= nerd would pay zillions of buckazoids for a NIB vic in 2019.
I thought that the VIC-20 DID have a bitmap mode, but because the unexpanded VIC didn't have enough RAM to have a full screen buffer it just wasn't used without expansion?
The redefinable character set could be laid out across the screen to mimic a true bitmap mode. Because of the optional double-high characters and small screen area, I think it was possible to cover the entire screen with unique characters. I'd have to look that up to be totally sure, but you could at least cover most of the screen. But it didn't have a true bitmap mode like the C64.
Multiply is a little faster than divide, so this should be a little faster. It's a lot faster if a machine supports a hardware multiply but not divide. (not that Microsoft bothered to support the hardware multiply on the TRS-80 Color Computer or MC-10) 20 PW=W2:PH=H2:IW=1/PW:IH=1/PH 60 X=ABS(T-INT((T+W)IW)PW) 70 Y=ABS(T-INT((T+H)IH)PH)
Partly what I came down here to say! But if you randomised T, just drew dots, and maybe made the dot larger, you could have an interesting slow screensaver-type display, right? Maybe do within one time range for a while, then another for a while, and so on.
CHALLENGE! Instead of using dots to progressively make lines from edge to edge of the box, use single lines to connect the edges, whilst still avoiding using IF/THEN statements. ;)
It might have been done to abstract out differences between the hi-res screen being 160×160 and the multicolor screen being 80×160. There's even a combination mode where you can have both on the same screen (in different color cells).
int W = 89; int H = 79; float PW = W*2; float PH = H*2; float T = 0; float X = 0; float OX = 0; float Y = 0; float OY = 0; float DX = 1; float DY = 1; int SX = 3; int SY = 3; int SW = (W+1)*SX; int SH = (H+1)*SY; final color DRAW_COLOR = color(3.0, 255.0, 34.0); void setup() { size(270,240); fill(DRAW_COLOR); } void draw() { line(OX*SX,OY*SY,X*SX,Y*SY); OX = X; OY = Y; X = X + DX; Y = Y + DY; X = abs(T - int((T+W)/PW) * PW); Y = abs(T - int((T+H)/PH) * PH); T = T + 1; }
My solution was to have DX and DY recalculated on every pixel: DX=DX*(1+((X=W or X=0)*2)) DY=DY*(1+((Y=H or Y=0)*2)) No IF statement, but is that cheating? No idea...
Just wondering : if all you can do to achieve hi-res graphics is modify the character set, how can you have the entire screen in hi-resolution? If you only have 255 possible characters to redefine, that's only about 11 rows of the screen filled with characters to redefine. Can anyone explain how the whole screen is altered to be hi-res? Thanks!
Double-height character mode is simplest. After that there are various tricks, including dynamically rewriting character definitions in sync with the raster. An example of what can be done these days: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-R5gDeHfJI8k.html
Hi Robin, I really love your channel and thnx a lot for all your videos, especially all the incredibly valuable c64 assembly info. Could you please show how a sid file loaded in memory to be played back while allowing a basic program to still run? I'm thinking the assembly code could be entered as decimal values to be poked in basic. How should the interrupts be set for the basic to continue while music is playing? I know that sid is converted to a .dat file to remove the header info but whatever I did I couldn't accomplish good results. I would really appreciate if you would make a video about this. Help me obi van kenobi, you're my only hope :-)
An interesting challenge! Can you reply with a link to a particular sid (maybe on CSDb) that you tried to get working? I'll give it a try to see if I can make a video of it. Besides the interrupt setup, memory use is the other problem. Many SIDs will interfere with BASIC's zero page memory use, and the SID itself will load into BASIC memory (commonly at $1000), so those problems will need to be dealt with.
@@8_Bit I've tried sids having init address at $1000 and play address at $1003 which i believe to the most common, to avoid issues but that didn't help much :-) I have another sid that inits at $C000 and plays at $C135. Do you think that would be more appropriate? I couldn't get those to work too. What I had in mind was to getting a basic code loading any sid file from disk (that is a sid converted to header stripped .dat or even better a if possible a regular sid) and have basic to trigger sid's player with decimal machine code in data statements poked with a for-next loop. I'm doing something similar in basic as a loader that loads a koala image with a viewer in machine language in basic data statements that shows a picture which then when a key is pressed, loads a menu driver program in basic. I really like the idea to run/automate machine code from basic, the main problem is to avoid assembly to take over input and basic automation completely, thus the issue with interrupts :-) here are the two disk images I've been working on. one is a game disk having koala image loaded from basic with machine code. the other having my three attempts to load sid from basic. I really hope you would shine some light on this :-) Thnx a lot. drive.google.com/drive/folders/1imHYJHKqkUrgwiQq-AqMzg8v0OYKK9w9
I've also included an indexed and searchable 6500 family programming manual in pdf which I've added clickable table of contents, clickable references, cleaned page images and etc. Thought you might like it.
Hey Robin, cool videos! I was just listening to Bochum Welt and seems that the cover graphics are rather VIC-esque... there's even some basic code on the back: www.discogs.com/Bochum-Welt-Module-2/release/8373 Wonder if the program would actually work or if it's just for show.
Yes, definitely looks like VIC-20 BASIC. The POKE is for the VIC-20 screen colour register too! And there's a bunch of PETSCII characters, and that's the VIC-20 mascot in the bottom right corner. The program certainly looks like it would work, printing out all 8 track names, having the user hit Return after each name is printed. Nice find!