Tutorial  Updated

DS Programming for Newbies!

3Lwpv.png

Table of Contents:

Introductory Chapters:
  1. Preparing the environment
  2. Variables!
  3. Functions!
  4. Operators in C
  5. Conditions - if/else Statements and switches
  6. Looping - for() and while() Loops
  7. Containers of Variables - Arrays and Structures
Introduction to DS Hardware:
  1. RAM and VRAM
  2. OAM and 2D Sprites
Practical use of libnds:
  1. Input: Keys and the Touchscreen
Practical Use of NightFox Lib:
  1. NightFox Lib Integration
  2. 2D MODE-0 Part 1 - Tiled Backgrounds
  3. 2D MODE-0 Part 2 - Tiled Sprites
Excercises:
  1. Your first program!
  2. MODE-0 Tiled Backgrounds Example
  3. MODE-0 Tiled Sprites Example
  4. Our very first game: Tic Tac Toe!
Additional Utilities:
  1. GRIT


:download: PDF Version maintained by CannonFoddr available on FileTrip HERE!

:download: PDF Version maintained by Pomegrenade GBAtemp Mirror HERE!




Preface


Hello and welcome! If you are reading this then it’s likely that you’re interested in getting to know more about programming for the Nintendo DS! If you are not, then you likely took the wrong turn, but let’s not get into that. Let’s also start with establishing one important thing – as the title suggests, this is a “From Zero to Hero” guide. If you are an experienced programmer then it is likely that you will not benefit from it much, if at all. It is going to introduce the very basics to users who have never even seen a compiler before and never coded in their life – stuff that you probably already know and aren’t interested in anymore. You are however still welcome as this is my first tutorial and will likely require a certain degree of proof-reading, plus, you may of course have useful suggestions! Keep in mind the target audience though, I’m doing my best not to introduce complicated concepts early on. If you’re not an experienced programmer or never programmed at all, this is a great place to start!

I’ve seen many guides approaching this subject – some were more helpful, some were rather vague, but there is one thing that was common in all of them, and it became apparent to me that something has to be done about it. The guides I’ve seen so-far are dedicated to users who are familiar with programming and only require an introduction to the DS environment, none of them are actually “tutorials” from the ground up. Does this mean that a non-experienced user simply cannot program for the DS or should not begin his adventure with programming on this exact platform? No, it does not! In fact, the DS is likely the easiest platform to program for when it comes to consoles – libnds is really not that hard to wrap your mind around and there are numerous libraries out there that facilitate programming for it even further. You probably want to ask: “If it’s so easy, why do You think it requires some sort of an explanation? The libraries are well-documented, do you expect the readers to be dill-wits who can’t follow simple examples?” and the answer to that is “No, in fact, I do believe that everybody is capable of programming, however one has to learn and acquire some basic programming habits and have some practice in C to be successful at it” and this is exactly the main goal of this tutorial. Depending on the interest shown by users and my workload at Uni this may or may not be a full-featured guide, however I promise that I will at least try to keep it up-to-date and expand upon it from time to time.

Now that the purpose is established, let’s move on to the juicy parts! I hope you will enjoy learning together and in case of any questions or suggestions, do write! Dear readers, keep in mind that the first few tutorials will be an incredibly rapid course in C, applicable to any type of programming, not just for the DS! We won’t be compiling much until this material is covered and thoroughly understood! So… Let’s get it on!
 
Last edited by Foxi4,

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
I`ve put a layer that cover all screen underneathe the scrolled layer, so emptyness is covered by it now. But it didn`t change anything.
I’d double-check if you definitely adjusted the declared background width/height to the new values, that doesn’t seem right. Even if the background is wrapping into blank space, it shouldn’t be glitching out like that. Did you enlarge the actual asset, GRIT it again and included that in place of the old one? Just changing the size figures won’t work either since your old map is not accounting for the new size.
 

Valkyrience

Member
Newcomer
Joined
Aug 12, 2023
Messages
14
Trophies
0
Age
25
XP
27
Country
Ukraine
Code:
#include <gl2d.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <nds.h>
#include <filesystem.h>
#include <nf_lib.h>


int main(void) {
    NF_Set2D(0, 0);
    NF_Set2D(1, 0);
    nitroFSInit(NULL);
    NF_SetRootFolder("NITROFS");
    NF_Set2D(0, 0);
    NF_Set2D(1, 0);
    NF_InitTiledBgBuffers();  
    NF_InitTiledBgSys(0);      
    NF_InitTiledBgSys(1);      
    NF_InitSpriteBuffers();    
    NF_InitSpriteSys(0);      
    NF_InitSpriteSys(1);      

    NF_LoadTiledBg("bg/sh", "sh", 512, 512);
    NF_CreateTiledBg(0, 3, "sh");  
    NF_LoadTiledBg("bg/tbg", "tbg", 512, 512);
    NF_CreateTiledBg(0, 2, "tbg");  
    NF_ScrollBg(0,2,-10,-10);

    NF_SpriteOamSet(0);
    NF_SpriteOamSet(1);
    swiWaitForVBlank();
    oamUpdate(&oamMain);
    oamUpdate(&oamSub);
    while(1){
       
        }  
    return 0;
}

I`ve create test project where i only create two BG 512x512 and scroll one. And it works fine if scroll value is zero or positive but on negative value scrolled layer dissapear. May be i don`t see some mistake in my code,
Post automatically merged:

Assets was enlarged GRITed and included.
Post automatically merged:

i got this on scrolling 0,0; 10,10; -10,-10;
Post automatically merged:

And if just roughly change size in this code to 256, i can scroll it in any direction
Post automatically merged:

Should I edit something in GRIT batch file for converting 512x512 BG?
 

Attachments

  • 2.png
    2.png
    10.2 KB · Views: 23
  • 3.png
    3.png
    9.2 KB · Views: 23
  • 1.png
    1.png
    6.7 KB · Views: 25
Last edited by Valkyrience,

plasturion

temporary hermit
Member
Joined
Aug 17, 2012
Messages
1,216
Trophies
2
Location
Tree
XP
3,505
Country
Poland
But what do you expect to be displayed when you scroll to the area where nothing exist? So backgrounds are repetitive? Good to know. Maybe would be better to scroll backward if you start in the center or right side of the map.

Infinity backgrounds? cool, maybe I'll test it someday.
Indeed, when I created big background (here 2560 x 512; larger than 1024px of any direction which is unsupported by dslib) in fact it's made on one layer of size 512x512, frame of background position and screen content is changing, image is reloaded with one screen offset when I reach one of any edge inside of this I guess virtual map dimesion. So probably this method belong as you said to bank switching. (one is loaded while other ones is displayed) However map actually is not so big and I could barely expand this dimension, maybe it would be possible with less assets I loaded concurently, didn't check it. I woudl like to look closer how is it realised, or not. Don't bother about it. ;]

bgscroll.png
 
Last edited by plasturion,

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
Code:
#include <gl2d.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <nds.h>
#include <filesystem.h>
#include <nf_lib.h>


int main(void) {
    NF_Set2D(0, 0);
    NF_Set2D(1, 0);
    nitroFSInit(NULL);
    NF_SetRootFolder("NITROFS");
    NF_Set2D(0, 0);
    NF_Set2D(1, 0);
    NF_InitTiledBgBuffers(); 
    NF_InitTiledBgSys(0);     
    NF_InitTiledBgSys(1);     
    NF_InitSpriteBuffers();   
    NF_InitSpriteSys(0);     
    NF_InitSpriteSys(1);     

    NF_LoadTiledBg("bg/sh", "sh", 512, 512);
    NF_CreateTiledBg(0, 3, "sh"); 
    NF_LoadTiledBg("bg/tbg", "tbg", 512, 512);
    NF_CreateTiledBg(0, 2, "tbg"); 
    NF_ScrollBg(0,2,-10,-10);

    NF_SpriteOamSet(0);
    NF_SpriteOamSet(1);
    swiWaitForVBlank();
    oamUpdate(&oamMain);
    oamUpdate(&oamSub);
    while(1){
      
        } 
    return 0;
}

I`ve create test project where i only create two BG 512x512 and scroll one. And it works fine if scroll value is zero or positive but on negative value scrolled layer dissapear. May be i don`t see some mistake in my code,
Post automatically merged:

Assets was enlarged GRITed and included.
Post automatically merged:

i got this on scrolling 0,0; 10,10; -10,-10;
Post automatically merged:

And if just roughly change size in this code to 256, i can scroll it in any direction
Post automatically merged:

Should I edit something in GRIT batch file for converting 512x512 BG?
Don’t test in DeSmuME, for starters. Are you seeing the same behaviour in No$GBA?
 

Valkyrience

Member
Newcomer
Joined
Aug 12, 2023
Messages
14
Trophies
0
Age
25
XP
27
Country
Ukraine
Don’t test in DeSmuME, for starters. Are you seeing the same behaviour in No$GBA?
I don't tested it in other emulators but my DSi shows same situation.
Post automatically merged:

I think I can surround my scrolled area with 256px empty area to evade negative values but it feels like crutch.
And it's irritating that when BG is 256 it works fine
 

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
I don't tested it in other emulators but my DSi shows same situation.
Right, for future reference use No$ for homebrew testing, DeSmuME is really only meant for retail titles. NF_ScrollBg(); uses signed arguments so there’s no reason why it should “glitch” like this, but on first glance I can’t see anything wrong with the snippet, so my suggestion would be to go with my first thought and center that area, then change your starting point from 0, 0 to 128, 128, or whatever maximum boundary you require. It doesn’t look like the scroll function likes going into the negative when you’re trying to bypass background wrapping, it definitely doesn’t like transparencies as the filler.

One thing to note, which could potentially be the problem, is your placement of V-blank and other updates:
NF_SpriteOamSet(0);
NF_SpriteOamSet(1);
swiWaitForVBlank();
oamUpdate(&oamMain);
oamUpdate(&oamSub);
All of these functions belong in the while loop, you need to refresh the screen every frame.
 

plasturion

temporary hermit
Member
Joined
Aug 17, 2012
Messages
1,216
Trophies
2
Location
Tree
XP
3,505
Country
Poland
here are some info from GBATEK DS:
2D Engines
Includes two 2D Engines, called A and B. Both engines are accessed by the ARM9 processor, each using different memory and register addresses:
Region______Engine A______________Engine B___________
I/O Ports 4000000h 4001000h
Palette 5000000h (1K) 5000400h (1K)
BG VRAM 6000000h (max 512K) 6200000h (max 128K)
OBJ VRAM 6400000h (max 256K) 6600000h (max 128K)
OAM 7000000h (1K) 7000400h (1K)

Engine A additionally supports 3D and large-screen 256-color Bitmaps, plus main-memory-display and vram-display modes, plus capture unit.
Let's say your assigned backgorund starts from 0x6000000 - first 128kb of vram
https://mtheall.com/banks.html#A=MBG0
when you start at 0,0 background position then scrolling on negative values equals you are trying to display bellow 0x6000000 memory, I sense it may happen everything due to volatile memory access.
 

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
here are some info from GBATEK DS:

Let's say your assigned backgorund starts from 0x6000000 - first 128kb of vram
https://mtheall.com/banks.html#A=MBG0
when you start at 0,0 background position then scrolling on negative values equals you are trying to display bellow 0x6000000 memory, I sense it may happen everything due to volatile memory access.
It technically shouldn’t because the background is wrapping and the value is signed - from the DS’ perspective it shouldn’t matter, and it didn’t matter until the border was introduced. The background *should* repeat infinitely. The only other solution would be to disable wrapping altogether by making the background affine instead of standard - with that type you get a flag that just disables wrapping and this whole situation can be avoided, which I suppose is another solution, but it doesn’t seem right. I might have to compile this myself and see what’s happening.
 
  • Like
Reactions: plasturion

Valkyrience

Member
Newcomer
Joined
Aug 12, 2023
Messages
14
Trophies
0
Age
25
XP
27
Country
Ukraine
One thing to note, which could potentially be the problem, is your placement of V-blank and other updates:

All of these functions belong in the while loop, you need to refresh the screen every frame.
I copied this part from night Fox examples. Where should I place vblank for better work
Post automatically merged:

Should GRIT bat file be edited for 512 px BG or it define size automatically? Maybe my assets are converted unpropelly?
 
Last edited by Valkyrience,

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
I copied this part from night Fox examples. Where should I place vblank for better work
All of it should be the last thing inside your main while() loop, the screen should refresh as the last thing in the program.

In any case, I’ve tested this matter on my end and I've tried all sorts of fixes, and my conclusion is this - the function absolutely refuses to scroll into the negative, you have to work with positive values. I don't remember this ever being the case, perhaps I simply never needed to go into the negative with a background myself, but 0 seems to be the absolute minimum. If I go below that, the background simply vanishes. I even recompiled nflib from scratch and reinstalled devkitPro several times, so the problem is repeatable, if it is a problem. The clever solution here is, once again, adding an offset. Realistically he map can be as big as you want, and you can scroll to any desired spot upon initialising the scene. Sorry to disappoint, I'll dabble a little bit in libnds to see if there's a workaround, but by the look of things @plasturion might be right and perhaps the register just doesn't like values like that. I was under the impression that it would handle it automagically, but that doesn't seem to be the case, or isn't the case anymore.
 

Valkyrience

Member
Newcomer
Joined
Aug 12, 2023
Messages
14
Trophies
0
Age
25
XP
27
Country
Ukraine
All of it should be the last thing inside your main while() loop, the screen should refresh as the last thing in the program.
In main project this part is located in the end of loop. I've placed it out of loop only in test project because I needed only one frame.

I'll probably make 256 px border with empty tiles to use only positive values.
Thank you so much for your help.
Post automatically merged:

But it still bothering me: why 256 px BG can scroll on negative values, it's strange
 

plasturion

temporary hermit
Member
Joined
Aug 17, 2012
Messages
1,216
Trophies
2
Location
Tree
XP
3,505
Country
Poland
Well i think nflib has build in some scroll engine. I tested background this size and even with 512x512 is treated same as any kind of big background. Actually the frame (displayed screen border 256x192) never wrap around but is supervised to be alltime whole inside, and when it reach one of the edge of screen change offset position with updated tiled background at the same time, just as i described before. Probably you could recive expected result with dslib.
 

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
Well i think nflib has build in some scroll engine. I tested background this size and even with 512x512 is treated same as any kind of big background. Actually the frame (displayed screen border 256x192) never wrap around but is supervised to be alltime whole inside, and when it reach one of the edge of screen change offset position with updated tiled background at the same time, just as i described before. Probably you could recive expected result with dslib.
Yes, there's a built-in scrolling engine for anything larger than 512x512, which is the maximum the DS can handle on paper. The way NFlib does this is by copying new rows/columns of tiles as needed, and when I scrolled by just using the registers, the background scrolled correctly, just without the necessary tile copying provided by NFLib. I'm checking if an older version of the devkitPro toolchain behaves in the same way.

In main project this part is located in the end of loop. I've placed it out of loop only in test project because I needed only one frame.

I'll probably make 256 px border with empty tiles to use only positive values.
Thank you so much for your help.
Post automatically merged:

But it still bothering me: why 256 px BG can scroll on negative values, it's strange
See comment above. Bare naked libnds supports 4 background sizes for tiled backgrounds - 256x256, 512x256, 256x512 and 512x512. The “infinite” background offered here uses clever copying tricks to extend beyond that. Somewhere along the line of a zillion devkitARM and libnds releases something must’ve changed that borked compatibility in NFLib, or it never supported negative values/wrapping and I never noticed. When using libnds I’m not experiencing this scrolling issue at all, I can scroll in either direction, but I’m limited to libnds sizes. Since NFLib is no longer maintained and I saw no obvious bugs or errors when compiling the library and the project, you’d be looking for a needle in a haystack trying to bugfix this. I’ll give it a glance when I have time, perhaps it’s an easy fix, but realistically you’re only using one extra tile, so the sacrifice isn’t great, and your other layers don’t have to match the size of the scrolling one.
 

plasturion

temporary hermit
Member
Joined
Aug 17, 2012
Messages
1,216
Trophies
2
Location
Tree
XP
3,505
Country
Poland
NFLib is maintained till now, it has just specific concept of handling and scrolling backgrounds. When nflib supervise and keep visible screen border inside you can relay on its own solution of copying rows and columns of tiles. When it reach 0 or max x,y it never copy from the other side of screen, but it leaves trash or empty space (max x,y), or switch off background (below 0,0) as we can test it. The assumption of this concept maybe that user never try to display something out of background bonduaries. As I remember nflib always worked like this, so border wraping is something new to me. :]
 
Last edited by plasturion,

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
NFLib is maintained till now, it has just specific concept of handling and scrolling backgrounds. When nflib supervise and keep visible screen border inside you can relay on its own solution of copying rows and columns of tiles. When it reach 0 or max x,y it never copy from the other side of screen, but it leaves trash or empty space (max x,y), or switch off background (below 0,0) as we can test it. The assumption of this concept maybe that user never try to display something out of background bonduaries. As I remember nflib always worked like this, so border wraping is something new to me. :]
Hmm, maybe my memory is failing me then, I haven’t had a super close look at the NFLib source yet, so I only have a vague idea how it works, but I understand the principle. It has been over a decade, so I’m not surprised. In my own programs I normally “gate kept” backgrounds - I’d just disable the camera scroll if I reached a screen boundary, which is easy to implement, that’s probably why I’ve never seen this behaviour before. :P

Yeah, standard tiled backgrounds in libnds always wrap, it’s a feature of the hardware. Thanks to this feature you can drop down a couple of layers and create great-looking scrolling parallaxes that really give games some depth. I was under the impression that NFLib would’ve preserved that for infinite backgrounds, but I suppose it would’ve been a pain to integrate it reliably for every single game as the offset required would’ve been different in every game. Unless you know exactly how fast the background is scrolling, you wouldn’t be able to copy new rows of tiles in time. Thanks for the reminder!
 

plasturion

temporary hermit
Member
Joined
Aug 17, 2012
Messages
1,216
Trophies
2
Location
Tree
XP
3,505
Country
Poland
Sure thing, you can still achive good result using nflib also with all the layers involved in use as you said for hardware parallax effects. I did this platform demo to test background capabilities powered by nflib some time ago. It's still great thing that compromise easy usage for implement and recive promissing results without digging in technical specification too much and all the hardware tricks based on tickling a registers. What I would like to add as extension of this library is output text monitor printing free and unavailable VRAM banks and reserved memory regions. Maybe it could be useful to trace what is happen and how much memory actually takes extedend backgrounds in example before and after NF_CreateTiledBg(). Perhaps it could be helpful to plan and predict optimal VRAM usage.
Don't want to spam too much but I want to boast that i take my lessons on this tutorial too. Thanks!
 

Attachments

  • SunnyLandDS_v02.7z
    128.7 KB · Views: 20
Last edited by plasturion,
  • Like
Reactions: Foxi4

Foxi4

Endless Trash
OP
Global Moderator
Joined
Sep 13, 2009
Messages
30,825
Trophies
3
Location
Gaming Grotto
XP
29,850
Country
Poland
Sure thing, you can still achive good result using nflib also with all the layers involved in use as you said for hardware parallax effects. I did this platform demo to test background capabilities powered by nflib some time ago. It's still great thing that compromise easy usage for implement and recive promissing results without digging in technical specification too much and all the hardware tricks based on tickling a registers. What I would like to add as extension of this library is output text monitor printing free and unavailable VRAM banks and reserved memory regions. Maybe it could be useful to trace what is happen and how much memory actually takes extedend backgrounds in example before and after NF_CreateTiledBg(). Perhaps it could be helpful to plan and predict optimal VRAM usage.
Don't want to spam too much but I want to boast that i take my lessons on this tutorial too. Thanks!
Hey man, boast all you want, it’s always nice to hear that your work was appreciated and actually led to some people making some cool things. I am the last person who expected this thread to get a quasi-revival over a decade later, but I’m happy to see that it did all the same. It actually made me touch devkitPro, albeit cautiously and with a stick, after many years of complete inactivity, so I’m having a bit of fun too. :lol:
 
  • Like
Reactions: plasturion

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: Nah we need a device where we can ask an assistant that can fit in our pockets too bad Samsung... +1