Jump to content

Search the Community

Showing results for tags 'tutorial'.

More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Atari Systems
    • Atari General
    • Atari 2600
    • Atari 5200
    • Atari 7800
    • Atari Lynx
    • Atari Jaguar
    • Atari VCS
    • Dedicated Systems
    • Atari 8-Bit Computers
    • Atari ST/TT/Falcon Computers
  • Classic Consoles
  • Classic Computing
  • Modern Consoles
  • Gaming General
  • Marketplace
  • Community
  • Community
  • Game Programming
  • Site
  • PC Gaming
  • The Club of Clubs's Discussion
  • I Hate Sauron's Topics
  • 1088 XEL/XLD Owners and Builders's Topics
  • Atari BBS Gurus's Community Chat
  • Atari BBS Gurus's BBS Callers
  • Atari BBS Gurus's BBS SysOps
  • Atari BBS Gurus's Resources
  • Atari Lynx Programmer Club's CC65
  • Atari Lynx Programmer Club's ASM
  • Atari Lynx Programmer Club's Lynx Programming
  • Atari Lynx Programmer Club's Music/Sound
  • Atari Lynx Programmer Club's Graphics
  • The Official AtariAge Shitpost Club's Shitty meme repository
  • The Official AtariAge Shitpost Club's Read this before you enter too deep
  • Arcade Gaming's Discussion
  • Tesla's Vehicles
  • Tesla's Solar
  • Tesla's PowerWall
  • Tesla's General
  • Harmony/Melody's CDFJ
  • Harmony/Melody's DPC+
  • Harmony/Melody's BUS
  • Harmony/Melody's CDFJ+
  • Harmony/Melody's General
  • ZeroPage Homebrew's Discussion
  • Furry Club's Chat/RP
  • PSPMinis.com's General PSP Minis Discussion and Questions
  • PSPMinis.com's Reviews
  • Atari Lynx 30th Birthday's 30th Birthday Programming Competition Games
  • 3D Printing Club's Chat
  • Drivers' Club's Members' Vehicles
  • Drivers' Club's Drives & Events
  • Drivers' Club's Wrenching
  • Drivers' Club's Found in the Wild
  • Drivers' Club's General Discussion
  • Dirtarians's General Discussion
  • Dirtarians's Members' Rigs
  • Dirtarians's Trail Runs & Reports
  • Dirtarians's Wrenching
  • The Green Herb's Discussions
  • Robin Gravel's new blog's My blog
  • Robin Gravel's new blog's Games released
  • Robin Gravel's new blog's The Flintstones Comic Strip
  • Atari Video Club's Harmony Games
  • Atari Video Club's The Atari Gamer
  • Atari Video Club's Video Game Summit
  • Atari Video Club's Discsuuions
  • Star Wars - The Original Trilogy's Star Wars Talk
  • PlusCart User's Bug reports
  • PlusCart User's Discussion
  • DMGD Club's Incoming!
  • DASM's General
  • AtariVox's Topics
  • Gran Turismo's Gran Turismo
  • Gran Turismo's Misc.
  • Gran Turismo's Announcements
  • The Food Club's Food
  • The Food Club's Drinks
  • The Food Club's Read me first!
  • The (Not So) Official Arcade Archives Club's Rules (READ FIRST)
  • The (Not So) Official Arcade Archives Club's Feedback
  • The (Not So) Official Arcade Archives Club's Rumor Mill
  • The (Not So) Official Arcade Archives Club's Coming Soon
  • The (Not So) Official Arcade Archives Club's General Talk
  • The (Not So) Official Arcade Archives Club's High Score Arena
  • Adelaide South Australia Atari Chat's General Chat & Welcome
  • Adelaide South Australia Atari Chat's Meets
  • Adelaide South Australia Atari Chat's Trades & Swaps
  • KC-ACE Reboot's KC-ACE Reboot Forum
  • The Official Lost Gaming Club's Lost Gaming
  • The Official Lost Gaming Club's Undumped Games
  • The Official Lost Gaming Club's Tip Of My Tounge
  • The Official Lost Gaming Club's Lost Gaming Vault
  • The Official Lost Gaming Club's Club Info
  • GIMP Users's Discussion
  • The Homebrew Discussion's Topics
  • Hair Club for Men's Bald? BEGONE!


There are no results to display.

There are no results to display.


  • AtariAge Calendar
  • The Club of Clubs's Events
  • Atari BBS Gurus's Calendar

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start










Custom Status



Currently Playing

Playing Next

Found 13 results

  1. For years now I've been hoping to see a series like this for various retro computing platforms (Atari 800, Apple II, TRS-80 Model III, Fujitsu FM7, C64, VIC-20, Atari ST, TI-99, SG-3000, X68000, Acorn, BBC Micro, Color Computer, PC-88, Spectrum, Adam, etc...). https://www.youtube.com/playlist?list=PLOT5j3ELi5BaSrb24fJEKvTqlRK4fg9wS In this case, it's for the Amiga. If others decide to make YouTube tutorial series' like this, please let me know. There are a bunch of platforms that I'd like to learn. And if someone can recommend a free video screen-capture utility that is Windows Vista compatible (and doesn't contain viruses), I may actually do more of these. Oh, and maybe an app that can add captions since YouTube is no longer offering annotation and captioning services as part of their site tools.
  2. If anyone is wanting to get started in Assembler the first part of my "How Not to Learn Assembler" column is in the new issue of Pro(c) Atari Magazine. It has a focus on game development and will cover beginner to intermediate topics, those more advanced may want to shout at the magazine as they read it but may get a laugh or two! If anyone wants to write anything covering anything at all, please send it to me for the next issue. Thanks, Jason
  3. Can somebody do video tutorial for TMC2? some basic steps, etc. please Or CMC, or other music composer..
  4. Hey there everyone, I just started learning to program the Atari 2600 in Assembly recently and I think that I have learned a great deal. However, I seem to have hit a road block. Initially, when I first started programming playfields and backgrounds, I plugged the values in line by line like this: .fctbNone{ color:#e0e0e0; }.fctbStyle0{ color:#adff2f;font-style:oblique; }.fctbStyle3{ color:#ffd700; }.fctbStyle5{ color:#ee82ee; }.fctbStyle4{ color:#00bfff; }.fctbStyle2{ color:#ffa500; }.fctbStyle1{ color:#00ffff;font-weight:bold; }.fctbStyle1Style3{ color:#00ffff;font-weight:bold; }.fctbStyle2Style3{ color:#ffa500; }.fctbStyle6{ color:#ff6347; }.fctbStyle0Style6{ color:#adff2f;font-style:oblique; }; < GAME TITLE >; < AUTOR > processor 6502 include "vcs.h" include "macro.h" ;---------- LABELS ----------;---------------------------- SEG ORG $F000Reset; Initialize TIA/RAM; ------------------ LDX #0 LDA #0 Clear STA 0,X INX BNE Clear ; Initialize Labels; ----------------- COMPILE_VERSION = NTSC NTSC =#1 LDA #%00000001 STA $82 LDA #$BC STA COLUPF LDA $82 STA CTRLPF ; Start Game; ----------StartOfFrame LDA #0 STA VBLANK LDA #2 STA VSYNC ; VSYNC Signal STA WSYNC STA WSYNC STA WSYNC LDA #0 STA VSYNC ; Vertical Blank LDX #0 VerticalBlank STA WSYNC INX CPX #37 BNE VerticalBlank ; Scanlines LDX #0IDIOT INX LDA #$C4 STA COLUBK STA WSYNC CPX #40 BNE IDIOT LDA #$C4 STA COLUPF LDA #$0 STA COLUBK LDA #%11111111 STA PF0 STA PF1 LDA #%10111111 STA PF2 MORAL INX LDA #$CA STA COLUBK STA WSYNC CPX #42 BNE MORAL LDA #%11100000 STA PF0 LDA #%11001111 STA PF1 LDA #%00011111 STA PF2CORAL INX LDA #$CA STA COLUBK STA WSYNC CPX #44 BNE CORAL LDA #%11000000 STA PF0 LDA #%10000111 STA PF1 LDA #%00001111 STA PF2NORAL INX LDA #$CA STA COLUBK STA WSYNC CPX #46 BNE NORAL LDA #%10000000 STA PF0 LDA #%00000011 STA PF1 LDA #%00000111 STA PF2STEVE INX LDA #$CA STA COLUBK STA WSYNC CPX #48 BNE STEVE LDA #%00000000 STA PF0 LDA #%00000001 STA PF1 LDA #%00000011 STA PF2PTEVE INX LDA #$CA STA COLUBK STA WSYNC CPX #50 BNE PTEVE LDA #0 STA PF0 STA PF1 STA PF2BIGB INX LDA #$CA STA COLUBK STA WSYNC CPX #110 BNE BIGB BIGBB INX LDA #$2E STA COLUBK STA WSYNC CPX #130 BNE BIGBB BIGBBB INX LDA #$2C STA COLUBK STA WSYNC CPX #150 BNE BIGBBB FED INX LDA #$0 STA COLUBK STA WSYNC CPX #192 BNE FED EndScreen LDA #%01000010 STA VBLANK ; Overscan LDX #0Overscan STA WSYNC INX CPX #30 BNE Overscan ; Next Frame ; ---------- JMP StartOfFrame ORG $FFFA .word Reset .word Reset .word Reset END Thanks all! But while I was continuing in the tutorials, I found that my original methodology isnt really going to work (or will it? please let me know!) especially working with a great deal of sprites and backgrounds. So, I have found that most people tend to do play fields more like this: .fctbNone{ color:#e0e0e0; }.fctbStyle0{ color:#adff2f;font-style:oblique; }.fctbStyle3{ color:#ffd700; }.fctbStyle5{ color:#ee82ee; }.fctbStyle4{ color:#00bfff; }.fctbStyle2{ color:#ffa500; }.fctbStyle1{ color:#00ffff;font-weight:bold; }.fctbStyle1Style3{ color:#00ffff;font-weight:bold; }.fctbStyle2Style3{ color:#ffa500; }.fctbStyle6{ color:#ff6347; }.fctbStyle0Style6{ color:#adff2f;font-style:oblique; }; < GAME TITLE >; < AUTOR > processor 6502 include "vcs.h" include "macro.h" ;---------- LABELS ----------;---------------------------- SEG ORG $F000Reset; Initialize TIA/RAM; ------------------ LDX #0 LDA #0 Clear STA 0,X INX BNE Clear ; Initialize Labels; ----------------- COMPILE_VERSION = NTSC NTSC =#1 LDA #%00000001 STA $82 LDA #$BC STA COLUPF LDA $82 STA CTRLPF PFG0 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010PFG1 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010PFG2 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010 .byte %10101010; Start Game; ----------StartOfFrame LDA #0 STA VBLANK LDA #2 STA VSYNC ; VSYNC Signal STA WSYNC STA WSYNC STA WSYNC LDA #0 STA VSYNC ; Vertical Blank LDX #0 VerticalBlank STA WSYNC INX CPX #37 BNE VerticalBlank ; Scanlines LDX #0 ;THIS AREA IS ENCLOSED FOR THE PASTEINGLDY #0Woah LDA PFG0,X STA PF0 LDA PFG1,X STA PF1 LDA PFG2,X STA PF2 INX STA WSYNC cpx #190 bne Woah;FINISH AREA LDA %00000000 STA PF0 STA PF1 STA PF2FED INX LDA #$0 STA COLUBK STA WSYNC CPX #192 BNE FED EndScreen LDA #%01000010 STA VBLANK ; Overscan LDX #0Overscan STA WSYNC INX CPX #30 BNE Overscan ; Next Frame ; ---------- JMP StartOfFrame ORG $FFFA .word Reset .word Reset .word Reset END So once I tested this I found that I only got some of the playfield filled, the other parts are random. why is this? Can it be fixed?
  5. So, I'm going to be away for a few weeks (more than a few) and away from my home-base where I can record new videos. So, in this thread I wanted to post those videos that have been created in the past couple weeks. I will be creating more, I know in the last video it appears it's the last, but it isn't, I just knew I'd be away for several weeks (i.e. 5ish due to work assignment out of town ). I have more ideas after this series that I want to develop but I won't be able to for at least a month and I have new items on order that have not arrived to review. So, it's not the end of the TI 99/4a Wagner's TechTalk videos. If you haven't seen these, I hope you take the opportunity to look around and hopefully it will be fun/helpful for you. Please comment below with any recommendations and I'll do my best to add them when I return in late April (I will have internet access, just not the ability to create new TI content as my TI will be at home and I won't be). Best to all! -Jon Part I - TI 99/4a Home Computer Introduction and History - Part I https://youtu.be/mFZgnH32Kag Part II - AWESOME TI 99/4a Upgrades - the nanoPEB - Part II https://youtu.be/hsQD0i4pZFk Part III - Preparing and Managing the nanoPEB CF Card with TI99dir - Part III https://youtu.be/cJ5v9d3LeJg Part IV - TI-99/4A Part IV - Various Upgrades: Video converters, TI99Sim, FlashRom99 and more! https://youtu.be/-0bffE-61qo
  6. Up for sale is a similar kit like I have been selling for the xbox1 but for the Wii, you get the Super Smash Brothers Game Disc, a great game by itself, TWO SD cards, one is a 1GB or 2GB card with the smash stack exploit, you also get an 8GB SD card with the Home Brew Chanel w/ Apps & Emulators and Roms. I will also assit you with the soft-mod and install process as it can be tricky. I found the youtube video for it that is currently up to be very UNhelpful on a key step in the process. cost for this kit is $35+shipping. [$45 if you want a 16GB SD card with even more roms and emus added] it will be in stock next week. I will post more details in this thread soon, I just wanted folks to be aware it was coming, the cost for JUST the Wii game on ebay these days is around $20-$25 shipped on average, you get the full package all set up for you, no searching, no bull. This will work on ANY Wii as Nintendo can not patch for this exploit, it is the best one for any Wii, in fact the instructions I give are to update your Wii before you do anything else. I will walk you through how to perform the soft-mod, install Boot-Mii, then HBC in that order so you can recover from a brick if it should happen. some Wiis will not let you install BootMii first, but all that will be covered in the tutorial I am putting together [you will either get SD or a MicroSD cards with adaptor, all depends on stock on hand] I will discount orders for those who supply their own SD cards, you need a small one to do the exploit with and the larger to use once HBC is installed. If you already have the game Super Smash Brothers for Wii, I can point you in the right direction to do it yourself or you can buy just the SD cards at a reduced rate. stay tuned for updates on this next week
  7. Forth: The Cart Before the Horse (#5) This is one is going to be brief. If you've read any of the Forth primers, or any of the Forth proclamations that I and others make here on Atariage from time-to-time, you'll no doubt have read about how versatile and configurable the language is. We're going to have a very brief look at that today. But it won't be the War And Peace tome that I wrote yesterday. Brian Fox recently wrote some fascinating code for Camel99 that gives the language a more Basic-like syntax. As you probably know, in Forth, arguments and parameters to words (functions) come *before* the word/function that you want to call. This is because words/functions take their data, and put their data on the stack, so the stack has to be loaded before the word is called: TI BASIC: CALL HCHAR(ROW,COLUMN,CHAR,REPEATS) Forth: ROW COLUMN CHAR REPEATS HCHAR This tends to put people off when they look at Forth. It just looks like gobbledy-gook; at least until you understand that ROW and COLUMN etc are going on the stack, and HCHAR removes them. However, Forth is supposedly "the most flexible language of them all", "ultra malleable, "if you don't like it you can change it" blah blah blah. So, why don't we put our money where our mouth is and prove it? Well alrighty then! Inspired by Brian's look at HCHAR and VCHAR I thought it might be fun to demonstrate how the language can be changed to suit your preferences. There are some restrictions, sure, but I think you'll be impressed. We're going to change Forth's HCHAR and VCHAR into TI BASIC's HCHAR and VCHAR, where the arguments come after the word. So, again, let's recap: TI BASIC: CALL HCHAR(ROW,COLUMN,CHAR,REPEATS) Forth: ROW COLUMN CHAR REPEATS HCHAR We're going to end up with: CALL HCHAR( ROW COLUMN CHAR REPEATS ) Furthermore, we want it to be sophisticated enough such that the parameters can be numbers (called literals in Forth parlance) or calls to other words, or complex Forth expressions that compute a value etc. What might shock you is how much code is NOT required to do this. I give you: : CALL ( -- ) ; IMMEDIATE \ do absolutely nothing : HCHAR( ASCII ) WORD EVALUATE STATE @ IF COMPILE HCHAR ELSE HCHAR THEN ; IMMEDIATE : VCHAR( ASCII ) WORD EVALUATE STATE @ IF COMPILE VCHAR ELSE VCHAR THEN ; IMMEDIATE Now, you can type this directly on the command line: PAGE CALL HCHAR( 10 10 42 10 ) CALL VCHAR( 10 10 42 10 ) And behold the awesomeness. Note the spaces: The space between the open parenthesis of HCHAR( and VCHAR( is essential. The spaces between the parameters are just normal for Forth (and actually looks much nicer than using commas). The space before the final closing parenthesis is also required. You just changed Forth to be more like BASIC. You don't have to have numbers in the parameter list. They can be words or expressions: 10 CONSTANT TEN 42 CONSTANT FORTY-TWO CALL HCHAR( TEN TEN FORTY-TWO TEN TEN + ) (That last phrase: TEN TEN + puts 10 on the stack, then another 10 on the stack, then + ("add") removes them and replaces them with their sum, thus leaving the repeat count for HCHAR) So how does it work? Let's look at CALL first. CALL does nothing. It's only job is to be there to make those more familiar with BASIC happy. It has no code in it; it's empty. Furthermore, it's what is known as an IMMEDIATE word, meaning that it executes DURING COMPILATION, not during execution. An example: : FRED ( -- ) CR ." I AM FRED" CR ; Type that in. Nothing much happens. The word FRED gets stored in the dictionary ready to be used. Now type FRED and press enter. FRED executes. No big deal. Now, type this: : BOB ( -- ) CR ." BOO! BOB WAS HERE!" CR ; IMMEDIATE Okay, you typed it in. Nothing much happened. Now execute it: type BOB and press enter. Again, no big surprises. Now, try this: : TOM ( -- ) BOB CR ." HELLO! I AM TOM!" CR ; Did you see what happened? While *TOM* was being compiled, BOB got in on the act and ran, rather rudely announcing his presence. So what happens if we run TOM (type TOM and press enter)? HELLO! I AM TOM! Where's BOB? Should BOB not also say BOO!? No. And the reason why is very clever and is the secret sauce that makes Forth so very powerful. Here it is: "Immediate words execute at compile time." That is, immediate words execute when a word is being compiled, *not* when the compiled word is executed! That's possibly a brain-hurting statement. Consider this TI BASIC code: 10 CALL HCHAR(10,10,42,10) Now, when you press enter, the TI BASIC compiler switches on and compiles your code into some internal magic code that will do what you want it to do when you later RUN it. Okay. All normal stuff. But consider this: When the TI BASIC compiler is compiling that line of code, it does so entirely privately. No have no control over what compiler does. Mind your own business, it's nothing to do with you. The compiler privately compiles that code (or doesn't if there's an error), and you are just a bystander. That's not the case in Forth. In Forth, you can use "immediate" words that run when the compiler is compiling. And because they run when the compiler is compiling, you can "hijack" the compiling process, and do something: make a fart sound; say something on the speech synth; load a file; anything you want. You can even compile your own code. Think about that. Code that compiles code. And THAT is what makes Forth so powerful. So, lets get back to TOM and examine what happened. In Forth, the compiler is switched on by : (colon) and switched off by ; (semi-colon): : SOME-WORD <CODE GOES HERE> ; The compiler just walks along the line of text, and when it sees a word it looks for it in its dictionary and if it finds it, it compiles a call (like a GOSUB) to it. Now you can see why spaces are so critical in Forth. They are what separate the words so that they can be found in the dictionary. However, when the compiler is looking for a word, if it finds it, it checks to see if it is immediate or not. If it is not, it just compiles a call/GOSUB to the word. However, if it *is* immediate, it *executes* it, and does not compile it. That means you can put a reference to an immediate word in your definition, and at that point in the compilation process it will call your immediate word, and *you* can do something to the word that is *currently* being compiled, like add some more code to it. When the immediate word ends, the compiler just carries on compiling, totally oblivious to anything you may or may not have done to the word currently being compiled. It's none of its business. It's your business. You are in total control. Thus when TOM was being *compiled* the compiler saw the reference to the word BOB and saw that it was "an immediate word" and so it executed BOB, and BOB did it's thing (in this case, writing a cheeky message to the screen) and then carried on with the compiling. Now you understand why, when TOM was *executed*, there was no message from BOB. BOB did it's thing while TOM was being *compiled*. Yes. In Forth, there are two distinct excecution phases: Run-time: When a word is just plain excecuting, doing its thang; Compile time: When a word is being compiled. And you can do whatever the hell you want in either phase. You might want to go for a little lie down at this point! Now, lets look at HCHAR( and see what it does: : HCHAR( ASCII ) WORD EVALUATE STATE @ IF COMPILE HCHAR ELSE HCHAR THEN ; IMMEDIATE When the compiler sees HCHAR( it sees that it is immediate and so it executes it. The first thing is does is place the ASCII code for a ) (closed parenthesis) on the stack. Then WORD executes. WORD reads the line of text and will stop when it sees the ) character. So, if you typed CALL HCHAR( 1 2 42 4 ) WORD would capture 1 2 42 4 The output of WORD is two numbers: The address and length of the text that it found. This is fed into EVALUATE that simply evaluates the string as if it were a line of code entered at the keyboard. In this case, 1 2 42 4, or TEN TEN 42 TEN etc. are all valid code, so it executes it according to the rules of Forth: If we're compiling (i.e. the compiler was switched on with : (so we're building a word) then it will compile what it sees; If we're not compiling, it will just execute what it sees there and then, just like in BASIC when you enter something without a line number. So, we're using EVALUATE to evaluate the parameters for us between the HCHAR( word and the closing ) character. Note the cheeky use of the open parenthesis in HCHAR( which makes it look like some part of the the syntax of the word, but it isn't: It's just part of the name! And note also the closing parenthesis which again looks like syntax but is in fact nothing more than a marker for WORD to look for to isolate the parameters so that it can feed them into EVALUATE. The magic of Forth. The last bit of HCHAR( is very simple indeed. It just looks to see if we're in compile mode (the variable STATE will be 0 if we're not compiling, and >0 if we are compiling). If we ARE compiling, we compile a call to HCHAR (the original version of HCHAR built into the TurboForth EPROM). See? We're "injecting" code into the definition that is being compiled. However, if we're NOT compiling, we just execute HCHAR right there and then, which uses the parameters that EVALUATE evaluated for us. Thus we can do: CALL HCHAR( 1 2 42 99 ) (i.e. not in a definition, so it will execute immediately, like BASIC code with no line number) Or : LINE ( -- ) CALL HCHAR( 1 2 42 10 ) ; And both will work fine and do what they're supposed/expected to do. So, again, here's what happens when that LINE defintion above is compiled: The compilier sees that CALL is an immediate word, so it runs it. CALL actually does precisely nothing, it compiles nothing and runs nothing. It has 0 impact on run-time speed. It's purely "syntactic sugar" to sweeten things up for BASIC lovers. It's a total sham. You don't need to use it at all. The compiler sees that HCHAR( is immediate so it runs it. HCHAR( temporarily takes over, and reads the input up to the closing parenthesis and evaluates them. Since we're building a definition (LINE) the compiler is ON, so EVALUATE will compile them (by calling a new instance of the compiler and saying "HEY! Compile this! Thanks man!" (How's that for a mind f**k!?). HCHAR( then exits, it's done it's thing. Control now goes back to the compiler. The compiler only sees ; (semi-colon) because the parameters were consumed by WORD and EVALUATE so it completes the definition and we're done. If you were to disassemble the definition of LINE what you would see is this: 1 2 42 10 HCHAR In other words, HCHAR( re-arranged the code so that the parameters went first, then called a reference to the internal (in the EPROM) HCHAR which expects the parameters to be on the stack. The whole HCHAR( definition is nothing more than a trick which allows us to put the parameters *after* HCHAR( but internally it compiles HCHAR after the parameters. And that is the power of Forth. If you don't like: ROW COLUMN CHAR REPEATS HCHAR You can make your own word to give you: CALL HCHAR( ROW COLUMN CHAR REPEATS ) Or any other combination. And there endeth the lesson. This is without a doubt a bit of mind melter when you are new to Forth, so don't worry if you don't understand it all. I just wanted to give you an appreciation of the power and flexibility of Forth. It's not essential to understand this stuff right now. And now a quick demo using our new words. We haven't covered a lot of the code below yet. For now, just sit back and enjoy. : FWD-BOX ( -- ) 30 0 DO 12 0 DO CALL VCHAR( I I I 33 + J + 24 I 2* - ) CALL VCHAR( I 31 I - I 33 + J + 24 I 2* - ) CALL HCHAR( I I I 33 + J + 32 I 2* - ) CALL HCHAR( 23 I - I I 33 + J + 32 I 2* - ) LOOP LOOP ; : REV-BOX ( -- ) 0 29 DO 12 0 DO CALL VCHAR( I I I 33 + J + 24 I 2* - ) CALL VCHAR( I 31 I - I 33 + J + 24 I 2* - ) CALL HCHAR( I I I 33 + J + 32 I 2* - ) CALL HCHAR( 23 I - I I 33 + J + 32 I 2* - ) LOOP -1 +LOOP ; : BOXES ( -- ) \ top-level - run me 1 GMODE 5 0 DO FWD-BOX REV-BOX LOOP 0 GMODE ." Thanks for watching!" CR ; Note the additional spaces in the paremeters so that it's easier to identify each paremeter. References: HCHAR - http://turboforth.net/lang_ref/view_word.asp?ID=220 VCHAR - http://turboforth.net/lang_ref/view_word.asp?ID=232 IMMEDIATE - http://turboforth.net/lang_ref/view_word.asp?ID=163 ASCII - http://turboforth.net/lang_ref/view_word.asp?ID=210 STATE - http://turboforth.net/lang_ref/view_word.asp?ID=189 COMPILE - http://turboforth.net/lang_ref/view_word.asp?ID=156 IF - http://turboforth.net/lang_ref/view_word.asp?ID=81 THEN - http://turboforth.net/lang_ref/view_word.asp?ID=88 ELSE - http://turboforth.net/lang_ref/view_word.asp?id=76 CONSTANT - http://turboforth.net/lang_ref/view_word.asp?ID=157 CR - http://turboforth.net/lang_ref/view_word.asp?ID=129 ." - http://turboforth.net/lang_ref/view_word.asp?ID=206 DO - http://turboforth.net/lang_ref/view_word.asp?ID=75 LOOP - http://turboforth.net/lang_ref/view_word.asp?id=84 +LOOP - http://turboforth.net/lang_ref/view_word.asp?id=69 I - http://turboforth.net/lang_ref/view_word.asp?ID=80 J - http://turboforth.net/lang_ref/view_word.asp?ID=82
  8. I know this is very elementary, but I have a couple simple questions for you guys. LOOP BLWP @VSBW INC R0 DEC R2 JNE LOOP How does JNE know to look at R2 here... is it the fact that R2 was the last register referred to in the source? For instance, if the code was written: DEC R2 INC R0 JNE LOOP Then would JNE look at R0? I don't have any reference material on me right now, and my slow-ass tethered internet is not allowing me to DL anything to help me out. Sorry. =) **I have a couple more questions as well, but I'm going to read through the assembly threads on here before I start asking questions which have already been answered. This forum is amazing for knowledge. =)
  9. So a friend sent me a private message asking me questions about the three topics in the subject. Instead of answering him in private I thought I'd just make a post about it so other people can also learn a couple of things! The message described a map of 16x16 pixel tiles forming a 16 by 8 tile grid. So, 288x160 pixels. As usual, the code and assets is up on github and you can download it using the usual ways. (Standard disclaimer: if the rest of this post seems alien to you then please go and read the pinned tutorials in this subforum. Hopefully things will become more clear then. If you're still confused, drop a line below!) Firstly, I needed some tile assets and instead of drawing my own hideous things and get depressed I just went into opengameart.org and grabbed a random 16x16 tileset. Originally it had way too many colours so I decreased them to 256 and saved the result as a 8-bit BMP file. I could have gone down to 16 but I didn't want to degrade the quality too much. Also I extracted a 16x16 tile to be used as our main sprite. Because I obviously ran out of paletted colours since they were spent in the background I just made the sprite 16-bit on the grounds that a) this is a demonstration, b) it shouldn't burn too much bandwidth anyway. Then I created a new project from the console build gridsprite new ___ _ ___ _ _ | _ \__ _ _ __| |_ ___ _ _ | _ ) __ _ __(_)__ _| |_ | / _` | '_ \ _/ _ \ '_| | _ \/ _` (_-< / _|_ _| |_|_\__,_| .__/\__\___/_| |___/\__,_/__/_\__| |_| |_| C:\svn\raptor\RB_~1\include\template\assets.txt C:\svn\raptor\RB_~1\include\template\rapapp.s C:\svn\raptor\RB_~1\include\template\rapinit.s C:\svn\raptor\RB_~1\include\template\rapu235.s C:\svn\raptor\RB_~1\include\template\template.bas C:\svn\raptor\RB_~1\include\template\ASSETS\partipal.bmp C:\svn\raptor\RB_~1\include\template\ASSETS\fonts\f_16x16.bmp C:\svn\raptor\RB_~1\include\template\ASSETS\fonts\f_8x16.bmp C:\svn\raptor\RB_~1\include\template\ASSETS\fonts\f_8x8.bmp 9 File(s) copied Project gridsprite created successfully! Great! Let's start butchering it up. First stop is rapapp.s where we change sound engine to Zerosquare's: player equ 0 ;0=Zerosquare's player, 1=U-235 player Next stop: assets.txt - we need to tell the system to import our graphics: abs,tiles,gfx_clut,ASSETS\GFX\hyptosis_tile-art-batch-1.bmp abs,scrbuf,gfx_noclut,ASSETS\GFX\playfield.bmp abs,sprite,gfx_noclut16,ASSETS\GFX\sprite.bmp First is our huge spritesheet, with palette export. Then comes a placeholder image that will serve as our screen buffer (where we'll draw the tiles). This could have been blank but sometimes it helps having a non-blank image (for debugging). Lastly, our small 16bit sprite. Now we need to define our graphics objects for raptor, which means editing the dreaded rapinit.s file. Ugh! So we need to add two objects to the existing file, one will display the screen buffer and the other will display the sprite. We do that by copying the template (the block of text which is commented out) and adjusting only, a few parameters, namely the sprite_gfxbase field to point to the addresses of our graphics (scrbuf and sprite from above), the BIT DEPTH (8 and 16 respectively), sprite_bytewid (288 and 16*2 respectively), sprite_width (288/16), sprite_height (160/16), sprite_gwidth (288/16). The other stuff, don't know, don't care, leave as is, it's "fine"! After the unpleasant stuff we're now ready to start codin' - woohoo! Drawing the tiles First of all, the tile map. This was mostly reused code from another project (drawmap). It has been however modified for the parameters of our problem here and the code slightly modified to be more readable (and faster!). The original post for drawmap is here: https://atariage.com/forums/topic/263485-rb-manic-miner/?do=findComment&comment=3724346 To begin, we need an array to store our grid tiles. This will hold numeric values. dim map[map_height][map_width] as short Notice how we need to define height*width. In most cases it won't hurt to define that the other way, but if we then would like to fill in the indices as a huge stream of values it can get quite weird. Just trust me on this one, I don't like it either as I'm used to think of width*height when defining arrays :). The routine also needs a few definitions: ' The screen to draw the map's width in bytes. ' Think of this as <width in pixels>*<bits per pixel>/8 const dest_screen_width_in_bytes=288 ' Our tile's height const tile_height=16 ' Our tile's width in bytes. ' Think of this as <width in pixels>*<bits per pixel>/8 const tile_width_in_bytes=16 ' The screen to read the tile's width in bytes. ' Think of this as <width in pixels>*<bits per pixel>/8 const src_screen_width_in_bytes=960 ' Map width inside the map array const map_width=18 ' Map height inside the map array const map_height=10 dim x as short dim y as short dim c as short dim tilex as short dim tiley as short These are really definitions coming from our map size as a grid, our spritesheet dimensions, our tile dimensions and our screen buffer dimensions. I think it's pretty straightforward. (by all means, shout if something is not clear!) To populate the map I didn't want to spend ages drawing an actual map and exporting the values, so I opted to draw the tiles in the order they appear on the spritesheet. So we fill our map using a simple loop. ' Fill map with some tiles for y=0 to map_height-1 for x=0 to map_width-1 map[y][x]=60*y+x next x next y There we go, our map is now ready to be displayed. This could be filled using proper values from a tile editor but this is out of scope for this post. (Perhaps in another I'll get something like Tiled to export maps.) This loop will display the map to our screen buffer: ' Draw map for y=0 to map_height-1 for x=0 to map_width-1 c=map[y][x] tilex=(c % (src_screen_width_in_bytes/tile_width_in_bytes)) tiley=(c/(src_screen_width_in_bytes/tile_width_in_bytes)) drawtile(x,y) next x next y Easy, just loop through all possible x and y values for width and height, find the coordinates of the tile from our spritesheet and the screen coordinates the tile will be shown and tell drawtile to go draw the thing! So the only thing missing is drawtile routine. Brace yourselves: ' Draws a 16 x map_height tile on screen. ' x is multiplied by map_width and y is multiplied by map_height sub drawtile(x as SHORT, y as SHORT) local i as short local screen_y_offset as LONG local screen_x_offset as LONG local screen_address as LONG local tile_y_offset as LONG local tile_x_offset as LONG local tile_address as LONG tile_y_offset=tiley*(src_screen_width_in_bytes*tile_height) tile_x_offset=tilex*tile_width_in_bytes tile_address=(LONG)strptr(tiles)+tile_x_offset+tile_y_offset screen_y_offset=y*(dest_screen_width_in_bytes*tile_height) screen_x_offset=x*tile_width_in_bytes screen_address=(LONG)strptr(scrbuf)+screen_x_offset+screen_y_offset for i=0 to tile_height-1 ' Our tiles are 16 pixels wide in 8bpp mode, which means they are 16 bytes wide in RAM. Hence we need 4 LPOKEs per line. lpoke screen_address,lpeek(tile_address) lpoke screen_address+4,lpeek(tile_address+4) lpoke screen_address+8,lpeek(tile_address+8) lpoke screen_address+12,lpeek(tile_address+12) screen_address+=dest_screen_width_in_bytes tile_address+=src_screen_width_in_bytes next i end sub Just think of it as something that takes the values we filled above and turns it into pixels on screen. The only hardcoded bit here is that it assumes that the tile width is 16 pixels and we're using 8bpp mode, otherwise it's quite generic. Again, if people want me to remove that restriction, ask! Randomness This has been discussed in various threads on this subforum and people have been reporting various degrees of success, so let's clear the air a bit with some theory and code. First of all, there is no easy way to get pure randomness out of deterministic systems like the Jaguar - boot time is pretty much the same, there's no easy register to sample and get something random, and even then who knows how "random" it will be. So let's throw that problem to the user! ' Initialise our random values ' The trick here is to keep re-runninf randomize with a running counter ' and wait till the user presses something. So in essence the user is generating ' the randomness RLOCATE 0,180 RPRINT "Press any button to begin countdown" do randomize(c) c+=539 ZEROPAD() loop until zero_left_pad BAND (~(Input_Pad_C1|Input_Pad_C2|Input_Pad_C3)) What does this dumb loop do? Very simple, it just waits for someone to press a button on the joypad. ....of course while doing that it keeps a running counter which is used to change the random function's initial seed :). Unless we're dealing with a person in possession of extraordinary abilities, there's probably no way they can hit the button at the exact moment twice. And even then our counter will not start from 0 each time this is called. So let's say we have a pretty good random seed going on here! Finding our coordinates Now we want to know if we have a character running around the screen on top of the tile map where they are. Remember, our sprite's coordinates are from 0 to 288-16 for x and 0 to 160-16 for y, but our map is 16x10. How can we convert from one system to another? do vsync ZEROPAD() if (zero_left_pad band Input_Pad_Up) and sprite_y>0 then sprite_y-- endif if (zero_left_pad band Input_Pad_Down) and sprite_y<160-16 then sprite_y++ endif if (zero_left_pad band Input_Pad_Left) and sprite_x>0 then sprite_x-- endif if (zero_left_pad band Input_Pad_Right) and sprite_x<288-16 then sprite_x++ endif rlist[2].x=(16+sprite_x)<<16 rlist[2].y=(16+sprite_y)<<16 RLOCATE 0,192 print "x=";sprite_x;", y=";sprite_y;", map x=";int((sprite_x+8)/16);", map y=";int((sprite_y+8)/16) RLOCATE 0,180 loop This is a sort of main loop. We check the joypad for up/down/left/right and update the coordinates of the sprite (rlist[2] means the second raptor object, which we defined as our sprite). The print statement then converts the sprite_x and sprite_y coordinates into grid coordinates simply by dividing by the grid width and height respectively (which is conveniently 16 in both cases). If we do that calculation we will notice something strange. Here is a screenshot from the binary which has our character (the heart if you haven't figured it out!) within a grid square. Let's say that the grid coordinates are x=3, y=2. There is no problem here, when we do the divisions described above we will get our x=3,y=2 nicely. Now let's consider another example: So now we're just passed right of the x=3, y=2 grid. So then we'd want our coordinates to be x=4, y=3. The thing is - we'll still get x=3, y=2! Why this is happening? Well, let's have a look at the sprite itself: Our sprite_x and sprite_y coordinates actually point to the top left corner of the sprite. This means that if we place our sprite at coordinates (0,0) and keep moving the sprite to the right, sprite_x/16 will transition from 0.something to 1.something only when sprite_x is larger than 16. This means that the top left corner will be at (16,0), so graphically our heart will be at the middle of the tile. So in order to fix this, we have to add half the sprite width and height to sprite_x and sprite_y before we perform the divisions. Easy! Now our coordinates will map a bit better to the grid coordinates! Getting a countdown timer for PAL/NTSC One last thing before this post comes to a finish, is how to create a countdown timer. The Jaguar hardware has no easy way to count the time unless you start using DSP timers or something equally bizarre. And you probably don't need that much precision or want to mess around with those timers. But at least we do have the Vertical BLank interrupt, or VBL for short. This is an interrupt that fires at a fixed rate when the screen is ready to be drawn from the beginning. This happens every 50 times for PAL and 60 times for NTSC. So if we can count the VBL ticks then we have a sort of clock! rb+ has a command which waits until such an interrupt is generated: VSYNC so let's use that! But first we need to know if our system is PAL or NTSC. Turns out there's a hardware register that gets set with the correct value. So we can use that to see how many VBL ticks equals one second: ' Determine screen frequency dim ticks_per_second as short ticks_per_second=50 ' assume pal if (dpeek(CONFIG) band VIDTYPE)<>0 then ticks_per_second=60 ' nope, it's ntsc endif Now we can set a countdown timer: ' Initialise our countdown timer dim countdown_ticks as short countdown_ticks=10*ticks_per_second Then it's a simple matter of having a loop that VSYNCs and ticks our timer variable down until it's zero: do vsync if countdown_ticks>0 then print "Seconds left: ";(float)countdown_ticks/(float)ticks_per_second countdown_ticks-- else RPRINT "It's over!!!!!!!!!!!!!!!!!!!!!!!!!!" endif loop And that's it! Hopefully this has been helpful to people, I really tried to make it as accessible as possible for people that are learning things. Let me know what you think about it, and more importantly: ask if something is not clear. See you around!
  10. Found this excellent BASIC programming tutorial for the ZX-81 - Awesome presentation and observations illustrate the fun of 80's programming in 1K of BASIC on the ZX81 inspiring creativity with a clearly illustrated walk through building a complete Pong game with tips and tricks for optimizing program size and reducing flicker.
  11. It's been a few years now since I last did an example, so I guess it was time for a new one (plus I've been asked very politely by somebody)! Get the latest revision of the repository and build project "vertscroller". I'm sorry that the code is without comments and cryptic, but I'm quite tired tonight and I'm sure that if I tried to explain how it works people would have even more questions :). I'll just say that it uses a 320x480 buffer and each new line of text is printed twice. So I guess people in the know already got the idea. The rest, try to figure out on your own for now (it's a good excercise to be honest!) and don't hesitate to ask questions! That's it for now, have fun taking it apart!
  12. As I mentioned over in the homebrew forum, here's a demo/source/tutorial/etc showing a way to aim projectiles at a target. It's basically a way of setting the X and Y speeds of a projectile based on the coordinates of the firing enemy and the target. The source has some commented out code that can make the enemy a little less precise at aiming, which can be good for having it spread it's fire out. You can move the player with player 1 controls, or the enemy with player 2 controls. binaries, source, and a zip of both attached. aim.bas.a78 aim.bas.bin aim.zip aim.bas
  13. Hello Everyone, I took the liberty of opening a new topic on the tutorial series. The main reason (besides my big ego) is that the notifications on new parts and potential discussion is now scattered throughout the Atari Lynx and Programming forum and multiple topics. Also, it gives a single, easy to find location for the source code that goes with the tutorials. So, for your convenience, here is the list of tutorial parts: Part 1: Getting started Part 2: Development environment for Windows Part 3: Analyzing Hello World Part 4: Creating a project Part 5: Exploring TGI Part 6: Colors Part 7: Basics of sprites Part 8: Changing appearances Part 9: Advanced sprites Part 10: Collisions Part 11: Pens and more collisions Part 12: Memory mapping Part 13: UART Part 14: Timers Part 15: Memory and segments Part 16: Cartridges Part 17: Interrupts Part 18: Files Let me know if you find things unclear, wrong, have suggestions for topics, see room for improvement or anything else. I hope you will find it useful and take up the programming challenge. You can take my word for it, or that of Karri, ninjabba, Matashen, sage, GadgetUK, vince, obschan, TailChao, Sebastian, Wookie, Shawn Jefferson, toyamigo, or any of the other developers: it is a lot of fun. I've added the sources, tools and documentation for the CC65 2.13.9 SVN 5944 which is a known stable build. Remove the .txt extension for the sources archive. cc65-snapshot-win32- cc65-snapshot-doc- cc65-snapshot-lynx- cc65-snapshot-sources- Tutorials26082016.zip
  • Create New...