-. 스타일러스 따라 다니기
Demos/FollowStylus/ 예제를 봅시다.
s32 x = (128) << 8; // ship x position in 8bit fixed point
s32 y = (96) << 8; // Y
u16 angle = 0; // direction in which to move !
 
while(1)
{
angle = PA_GetAngle(x>>8, y>>8, Stylus.X, Stylus.Y);
PA_SetRotsetNoZoom(0, 0, angle); // Turn the ship in the correct direction

if (Stylus.Held){ // Move forward
x += PA_Cos(angle);
y -= PA_Sin(angle);
}
 
PA_OutputText(1, 5, 10, "Angle : %d  ", angle);

PA_SetSpriteXY(0, 0, (x>>8)-16, (y>>8)-16); // Sprite position converted to normal...

PA_WaitForVBL();
}
x, y는 sprite의 좌측상단이 아니고 중앙 위치이다. 이유는 더 나은 결과를 주기 때문이다.
angle = PA_GetAngle(x»8, y»8, Stylus.X, Stylus.Y); 이번에는 sprite 중앙과 스타일러스를 이용하여 각도를 구한다. 전에 궤도 예제와는 완전히 다르다.
if (Stylus.Held) 는 스타일러스가 눌려 졌을때 움직이게 하기위해 변경했다.

-. 원반 던지기와 튕기기
다음 3단계로 진행할 것이다.
1.먼저 양쪽 화면에서 스타일러스로 던진 주위를 날아 다니는 원반을 표시
2.그후에 구조체 배열을 사용하여 10개 원반을 가진 코드로 수정
3.끝으로 충돌 코드를 추가

원반 1개
스타일러스와 원반을 잡고, 던지고, 양쪽 화면에서 벽에서 튕기고 회전하는 방법을 보자.
Demos/Frisbee 예제를 보자.
#define FRISBEE 10 // Sprite number...
#define SCREENHOLE 48 // Size of the space between the screens... This is what looked the best
 
 
typedef struct{
s16 x, y; // This is for the frisbee's position
s16 vx, vy; // Frisbee speed
s16 angle; // To make the frisbee turn on itself
}frisinfos;
 
frisinfos frisbee;  // Frisbee structure variable
 
 
int main(void)
{
 
// Initialise the lib...
PA_Init();
PA_InitVBL();
 
PA_InitText(1, 0);
 
// Load the palettes for the sprites on both screens
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
 
// Create the sprite on both screens...
PA_DualCreateSprite(FRISBEE, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, 96, 300); // Bottom screen
PA_DualSetSpriteRotEnable(FRISBEE, 0); // Enable rotation/zoom, rotset 0
 
// Sprite initial position...
frisbee.x = 96+16;
frisbee.y = 300+16; // on the bottom screen
 
// Speed of frisbee in both ways
frisbee.vx = 0;
frisbee.vy = 0;
 
while(1)
{
// Move with the stylus, or move on...
if (PA_MoveSprite(FRISBEE)){
frisbee.x = PA_MovedSprite.X;
frisbee.y = PA_MovedSprite.Y + 192 + SCREENHOLE;
frisbee.vx = PA_MovedSprite.Vx; frisbee.vy = PA_MovedSprite.Vy;
}
else{
// Now, the frisbee's fixed point position will be updated according to the speed...
frisbee.x += frisbee.vx;
frisbee.y += frisbee.vy;

// If the sprite touches the left or right border, flip the horizontal speed
if ((frisbee.x -16 <= 0) && (frisbee.vx < 0)) frisbee.vx = -frisbee.vx;
else if ((frisbee.x + 16 >= 256)&&(frisbee.vx > 0)) frisbee.vx = - frisbee.vx;

// Same thing, for top and bottom limits...
if ((frisbee.y -16 <= 0) && (frisbee.vy < 0)) frisbee.vy = -frisbee.vy;
else if ((frisbee.y + 16 >= 192 + 192 + SCREENHOLE)&& (frisbee.vy > 0)) frisbee.vy = - frisbee.vy;
// The bottom limit is at the bottom of the bottom screen, so that would be 2 screen heights, plus the space in between...
PA_DualSetSpriteXY(FRISBEE, frisbee.x-16, frisbee.y-16);
}

PA_OutputText(1, 2, 10, "SpeedX : %d    ", frisbee.vx);
PA_OutputText(1, 2, 11, "SpeedY : %d    ", frisbee.vy);

frisbee.angle+=4; // Make the frisbee turn...
PA_DualSetRotsetNoZoom(0, frisbee.angle);
 
PA_WaitForVBL()// Synch to the framerate...
}

#define FRISBEE 10 // Sprite number...
#define SCREENHOLE 48 // Size of the space between the screens... This is what looked the best
쉽게 만들기 위해 2개의 정의가 있는데 FRISBEE 는 원반 sprite 수이고 SCREENHOLE 은 화면 사이의 픽셀 공간이다.
// Load the palettes for the sprites on both screens
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
 
// Create the sprite on both screens...
PA_DualCreateSprite(FRISBEE, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, 96, 300); // Bottom screen
PA_DualSetSpriteRotEnable(FRISBEE, 0); // Enable rotation/zoom, rotset 0
팔레트를 로딩하고 sprite를 회전이 가능하게 하고 양쪽 화면에 생성한다. sprite 의 Y 좌표가 300 인것에 주목하자. 이것은 하단 화면에 있는 것이다. 듀얼모드에서 PAlib는 DS를 384+SCREENHOLE 픽셀의 단일 화면처럼 간주하게 한다.
원반 구조체 초기화한다.
frisbee.x = 96+16;
frisbee.y = 300+16; // on the bottom screen
 
frisbee.vx = 0;
frisbee.vy = 0;
위치는 96, 300으로 설정한다. +16은 sprite의 중심을 사용할려고 하기때문이다. sprite은 32x32 이다. 속도는 0 이다. 이것은 고정 소수점을 사용하지 않는다.
다음이 중요한 부분중 하나이다.
if (PA_MoveSprite(FRISBEE)){
frisbee.x = PA_MovedSprite.X;
frisbee.y = PA_MovedSprite.Y + 192 + SCREENHOLE;
frisbee.vx = PA_MovedSprite.Vx; frisbee.vy = PA_MovedSprite.Vy;
}
PA_MoveSprite(sprite number) 는 스타일러스가 sprite을 터치했는지 검사하고 스타일러스 위치에따라 그 주위를 움직이다. 만일 스타일러스를 움직이면 그것은 돌아 올것이다.
frisbee.x = PA_MovedSprite.X; 로 원반의 새로운 X, Y 좌표를 기억시킨다.
PA_MovedSprite.X 는 sprite의 중심위치를 반환한다.
PA_MovedSprite.Y + 192 + SCREENHOLE; 를 사용한 이유는  MoveSprite 함수가 하단 화면에서 sprite의 위치를 반환한다. 그래서 y 은 0-191 사이 값이 된다. 그러므로 단 하나로 2개 화면이 고려 되도록 하기위해 올바른 위치로 변환해야 한다. 그래서 상단 화면에 192와 화면사이 공간인 SCREENHOLE를 더한다.
스타일러스 속도를 수평, 수직으로 기억한다.(각각 vx, vy)

sprite가 터치되지 않았다면 다른 루프로 들어간다.
else{
// Now, the frisbee's fixed point position will be updated according to the speed...
frisbee.x += frisbee.vx;
frisbee.y += frisbee.vy;
특별한 것은 없고 현재 속도에 따라 sprite가 움직인다.
// If the sprite touches the left or right border, flip the horizontal speed
if ((frisbee.x -16 <= 0) && (frisbee.vx < 0)) frisbee.vx = -frisbee.vx;
else if ((frisbee.x + 16 >= 256)&&(frisbee.vx > 0)) frisbee.vx = - frisbee.vx;

// Same thing, for top and bottom limits...
if ((frisbee.y -16 <= 0) && (frisbee.vy < 0)) frisbee.vy = -frisbee.vy;
else if ((frisbee.y + 16 >= 192 + 192 + SCREENHOLE)&& (frisbee.vy > 0)) frisbee.vy = - frisbee.vy
화면 밖으로 원반이 이동하는지 체크한다. 만일 이런 경우면 올바른 방향으로 원반이 움직이도록 하기위해 속도가 바뀔것이다. Y 위치와 관련하여 192+192+SCREENHOLE 로 확인해야 한다는 것에 주목해야 한다. 양쪽 화면의 총 높이와 공간을 고려해야 하기때문이다.
 PA_DualSetSpriteXY(FRISBEE, frisbee.x-16, frisbee.y-16);
}
else 루프의 끝은 올바른 곳으로 sprite를 위치시키는 것이다. Dual 접두사를 주목해라. 양쪽 화면에 x, y는 중앙 위치이기 때문에 -16를 사용한다. 좌측 상단 위치값이 필요해서다.
frisbee.angle+=4; // Make the frisbee turn...
PA_DualSetRotsetNoZoom(0, frisbee.angle);
프레임당 4 PAlib 각도의 속도로 돈다. DualSetRotset 는 양쪽 화면에서 회전이 되게 만든다.

원반 10개
typedef struct{
s16 x, y; // This is for the frisbee's position
s16 vx, vy; // Frisbee speed
s16 angle; // To make the frisbee turn on itself
}frisinfos;
 
frisinfos frisbee[10]// 10 Frisbees !!
 
 
 
int main(void)
{
 
// Initialise the lib...
PA_Init();
PA_InitVBL();
 
PA_InitText(1, 0);
 
// Load the palettes for the sprites on both screens
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);
 
s32 i; // will be used in for loops to cycle through the frisbees...
 
PA_InitRand(); // Init the random stuff...
 
for (i = 0; i < 10; i++){
// Sprite initial position...
frisbee[i].x = (PA_Rand()%256)-16; // random position on the screen
frisbee[i].y = 192+SCREENHOLE + (PA_Rand()%192)-16; // random position on the bottom screen;

// Speed of frisbee in both ways
frisbee[i].vx = 0;
frisbee[i].vy = 0;

frisbee[i].angle = 0;

// Create the sprite on both screens...
PA_DualCreateSprite(FRISBEE+i, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, frisbee[i].x-16, frisbee[i].y-16);
PA_DualSetSpriteRotEnable(FRISBEE+i, i); // Enable rotation/zoom, rotset 0
}
 
while(1)
{
for (i = 0; i < 10; i++){
// Move with the stylus, or move on...
if (PA_MoveSprite(FRISBEE+i)){
frisbee[i].x = PA_MovedSprite.X;
frisbee[i].y = PA_MovedSprite.Y + 192 + SCREENHOLE;
frisbee[i].vx = PA_MovedSprite.Vx; frisbee[i].vy = PA_MovedSprite.Vy;
}
else{
// Now, the frisbee's fixed point position will be updated according to the speed...
frisbee[i].x += frisbee[i].vx;
frisbee[i].y += frisbee[i].vy;

// If the sprite touches the left or right border, flip the horizontal speed
if ((frisbee[i].x - 16 <= 0) && (frisbee[i].vx < 0)) frisbee[i].vx = -frisbee[i].vx;
else if ((frisbee[i].x + 16 >= 256)&&(frisbee[i].vx > 0)) frisbee[i].vx = - frisbee[i].vx;

// Same thing, for top and bottom limits...
if ((frisbee[i].y - 16 <= 0) && (frisbee[i].vy < 0)) frisbee[i].vy = -frisbee[i].vy;
else if ((frisbee[i].y + 16 >= 192 + 192 + SCREENHOLE)&& (frisbee[i].vy > 0)) frisbee[i].vy = - frisbee[i].vy;
// The bottom limit is at the bottom of the bottom screen, so that would be 2 screen heights, plus the space in between...
PA_DualSetSpriteXY(FRISBEE+i, frisbee[i].x-16, frisbee[i].y-16);

}
frisbee[i].angle+=4; // Make the frisbee turn...
PA_DualSetRotsetNoZoom(i, frisbee[i].angle);
}
frisinfos frisbee[10]; 10개의 원반을 위한 배열이다.
s32 i; 는 루프에 사용될 것이다.
PA_InitRand(); DS 상에서 시도할때 마다 다른 장소에 원반이 있게 하기위해서다.
원반 초기화 코드가 좀 바뀌었다.
for (i = 0; i < 10; i++){
// Sprite initial position...
frisbee[i].x = (PA_Rand()%256)-16; // random position on the screen
frisbee[i].y = 192+SCREENHOLE + (PA_Rand()%192)-16; // random position on the bottom screen;

// Speed of frisbee in both ways
frisbee[i].vx = 0;
frisbee[i].vy = 0;

frisbee[i].angle = 0;

// Create the sprite on both screens...
PA_DualCreateSprite(FRISBEE+i, (void*)frisbee_Sprite, OBJ_SIZE_32X32, 1, 0, frisbee[i].x-16, frisbee[i].y-16);
PA_DualSetSpriteRotEnable(FRISBEE+i, i); // Enable rotation/zoom, rotset 0
}
이것은 화면상에 무작위 위치를 만든다. 그 위치에 sprite를 생성한다.
sprite 숫자 대신에 FRISBEE+i 를 주목하라. 이것은 첫 원반이 FRISBEE(10)이 되고 다음은 FRISBEE+1(11) 이 된다.
rotset 도 같은 방식으로 각각의 수를 가진다.(0-9)
frisbee.x  대신에 frisbee[i].x 배열를 가진다. i 로 frisbee에 접근할수 있다. 데모 나머지에서 같은 것을 볼수 있다.
코드의 나머지 부분은 무한 루프에서의 변화이다.
for (i = 0; i < 10; i++){ 는 각각의 sprite을 연속으로 실행하기 위한 것이다.
나머지는 완전 동일하다. frisbee가 frisbee[i]로 바뀐것 뿐이다. 모든 원반은 하나씩 움직인다.

10개 원반 충돌
원반이 각각 서로의 내부로 들어가지 않도록 하기위한 기본 충돌 시스템을 추가하는 것이다.
 PA_DualSetSpriteXY(FRISBEE+i, frisbee[i].x-16, frisbee[i].y-16);
}

u8 j;
for (j = 0; j < i; j++){ // Test collisions for all frisbees with a smaller number...
if (PA_Distance(frisbee[i].x, frisbee[i].y, frisbee[j].x, frisbee[j].y) < 32*32) {
frisbee[i].vx = (frisbee[i].x - frisbee[j].x)/6;
frisbee[i].vy = (frisbee[i].y - frisbee[j].y)/6;
frisbee[j].vx = -frisbee[i].vx;
frisbee[j].vy = -frisbee[i].vy;
}
}
for (j = 0; j < i; j++) 이 루프에서 이상한 점이 없는가? 만일 루프를 첫번째처럼 한다면 0-10 이 될것이다. 하지만 여기선 0 부터 i 이다. 왜 그럴까?
벌써 루프안에서 모든 원반을 0-9를 포함하여 움직인다. 여기에 유사한 또다른 루프를 추가하여 모든 원반에대해 원반 0-9가 부딪치는지 테스트 할수 있다. 이것은 두가지 문제점을 이끈다. 모든 원반의 충돌을 두번 테스트한다. 예를들어 원반 0 vs 1를 테스트한후 1 vs 0 을 한다. 이것은 크나큰 시간 낭비다. 같은 번호를 두번 충돌 테스트한다. 예를들어 0 과 0 사이. 이것은 같은 원반이다. 그래서 충돌을 리턴할 것이므로 버그다.
이것을 피하기 위해 프레임에서 벌써 이동한 원반하고만 충돌 테스트를 한다. 직관적이지 않지만 다르게 테스트 해보자.
원반 0 : 어떠한 테스트도 하지 않는다.(만일 j<i가 존재하고 i는 0이면 어떤걸 하기전에 나간다)
원반 1 : 원반 0하고만 테스트한다. (단지 1보다 작은 원반이다.)
원반 2 : 원반 0, 1 과 테스트 한다. 원반 2와 다시 테스트하지 않는다.
원반 3 : 원반 0, 1, 2 와 테스트 한다.
등등 ..

다음으로 충돌 체크하는 것은 원형 충돌 코드이다.
(PA_Distance(frisbee[i].x, frisbee[i].y, frisbee[j].x, frisbee[j].y) < 32*32) 이것은 충돌한 것이 맞는지 두 원반 사이의 거리를 체크한다. 만일 이경우이면 충돌시 양쪽 원반의 속도를 변경한다. 다음은 첫번째를 위한 것이다.
frisbee[i].vx = (frisbee[i].x - frisbee[j].x)/6;
frisbee[i].vy = (frisbee[i].y - frisbee[j].y)/6;
원반 위치의 토대로 정의된 새로운 속도이다. 서로 떨어지며 움직이게 될 것이다.
frisbee[j].vx = -frisbee[i].vx;
frisbee[j].vy = -frisbee[i].vy;
이것은 두번째 원반이 반대방향으로 가게 한다. 원반이 움직이는 속도는 고려되지 않았다. 그래서 진짜 세게 부딪쳤거나 매우 느려도 같은 속도로 떨어지며 움직인다.
좀더 세밀한 속도 보정이 필요하면 다음 예제를 체크해 보라. 매우 효과적인 방법으로 속도를 고려하였다.

퍽 치기
다음 데모는 원반예제뿐아니라 원형 충돌 코드에서 얻었다. 화면 중앙에 퍽이 있다. 화면 중앙에 퍽이(파란 원) 있고 또다른 파란 원인 라켓이 있다. 라켓으로 퍽을 쳤을때 퍽은 모든 곳이든 튕겨 갈 것이다. 세게 칠수록 빠르게 간다.
typedef struct{
s16 x, y; // position
s16 vx, vy; // speed
}puckinfos;
 
puckinfos puck;
 
#define SCREENHOLE 48
 
int main(void){
 
PA_Init();
PA_InitVBL();

PA_InitText(1,0); // On the top screen
 
PA_DualLoadSpritePal(0, (void*)sprite0_Pal);

// This'll be the movable sprite...
PA_CreateSprite(0, 0,(void*)circle_Sprite, OBJ_SIZE_32X32,1, 0, 16, 16);
s32 x = 16; s32 y = 16; // Sprite's center position

// This will be the hit circle
PA_DualCreateSprite(1,(void*)circle_Sprite, OBJ_SIZE_32X32,1, 0, 128-16, 96-16);
puck.x = 128; puck.y = 96+192+SCREENHOLE; // central position on bottom screen
puck.vx = 0; puck.vy = 0; // No speed


while(1)
{
if (PA_MoveSprite(0)){
x = PA_MovedSprite.X;
y = PA_MovedSprite.Y;
}

// Collision ?
if (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE) < 32*32) {
// Collision, so we'l change the pucks speed to move it out of our 'raquette'
u16 angle = PA_GetAngle(x, y, puck.x, puck.y-192-SCREENHOLE); // New direction angle
u16 speed = (32*32-PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))/32; // The closer they are, the harder the hit was...
puck.vx = (PA_Cos(angle)*speed)>>8;
puck.vy = -(PA_Sin(angle)*speed)>>8;
}

puck.x += puck.vx;
puck.y += puck.vy;

// If the sprite touches the left or right border, flip the horizontal speed
if ((puck.x -16 <= 0) && (puck.vx < 0)) puck.vx = -puck.vx;
else if ((puck.x + 16 >= 256)&&(puck.vx > 0)) puck.vx = - puck.vx;
 
// Same thing, for top and bottom limits...
if ((puck.y -16 <= 0) && (puck.vy < 0)) puck.vy = -puck.vy;
else if ((puck.y + 16 >= 192 + 192 + SCREENHOLE)&& (puck.vy > 0)) puck.vy = - puck.vy;
// The bottom limit is at the bottom of the bottom screen, so that would be 2 screen heights, plus the space in between...
PA_DualSetSpriteXY(1, puck.x-16, puck.y-16);


 
PA_WaitForVBL();
}
return 0;
}

typedef struct{
s16 x, y; // position
s16 vx, vy; // speed
}puckinfos;
 
puckinfos puck;
전형적인 정의가 다시 사용되었다. 퍽의 위치와 속도를 저장하기 위해서다. 이 예제에서 가능하지만 고정 소수점을 사용하지 않았다.
팔레트를 로딩하고 sprite를 생성한다.
PA_DualCreateSprite(1,(void*)circle_Sprite, OBJ_SIZE_32X32,1, 0, 128-16, 96-16);
puck.x = 128; puck.y = 96+192+SCREENHOLE; // central position on bottom screen
puck.vx = 0; puck.vy = 0; // No speed
양쪽 화면에 퍽을 로딩하고 현재 위치와 속도를 설정한다.
if (PA_MoveSprite(0)){
x = PA_MovedSprite.X;
y = PA_MovedSprite.Y;
}
라켓 위치를 저장한다.(중앙 위치)
다음 부분이 새로운 코드이다. 치는 방법에 따라 다른 속도로 퍽을 칠 것이다. 정확한 방향으로 퍽을 보낸다.
if (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE) < 32*32) {
// Collision, so we'l change the pucks speed to move it out of our 'raquette'
u16 angle = PA_GetAngle(x, y, puck.x, puck.y-192-SCREENHOLE); // New direction angle
u16 speed = (32*32-PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))/32; // The closer they are, the harder the hit was...
puck.vx = (PA_Cos(angle)*speed)>>8;
puck.vy = -(PA_Sin(angle)*speed)>>8;
}
if (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE) < 32*32) 는 충돌인지 체크한다. 32는 두원사이의 거리이고 속도 문제로 사각형 거리를 사용하기 때문에 32x32이다.
puck.y-192-SCREENHOLE 를 사용하는 것은 퍽을 위해 높이에서 두 화면을 위한 좌표이다. 라켓은 하단 화면에만 있다. 그래서 상단 화면의 크기(192)와 화면 공간(sCREENHOLE)을 빼야 한다.
u16 angle = PA_GetAngle(x, y, puck.x, puck.y-192-SCREENHOLE); 는 퍽과 라켓의 중앙에서 형성된 각도를 구하기 위한 것이다. 퍽이 나가는 방향의 각도이다.
u16 speed = (32*32-PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))/32; 는 퍽의 속도를 결정한다. 칠때 퍽과 가까울수록 빠르게 움직인다. 이유는 1 픽셀로 퍽을 쳤다면 매우 느리게 움직였다는 것을 의미하기 때문이다. 하지만 16픽셀과 같이 퍽을 쳤다면, 프레임이 갱신되기전에 적어도 16픽셀을 움직였다는걸 의미하므로 1픽셀로 치는 것보다 16배 빠른것이다.
32x32는 치는데 필요한 사각형 거리이다. 만을 0픽셀로 충돌하면, 퍽을 치지 않는다. 속도가 충분히 높지 않기때문이다.
그때 거리 (PA_Distance(x, y, puck.x, puck.y-192-SCREENHOLE))는 다시 계산되고 사각형 거리에서 빼진다. 이것은 빨리 움직일때 더 높은 속도를 제공할 것이다.
마지막으로 속도는 32로 나누어지는데, 이유는 단지 시행착오로 구한 것이다. 더 높거나 낮은 속도로 바꿀수 있다. 조정이 필요하다.
puck.vx = (PA_Cos(angle)*speed)>>8; 는 새로 부딪칠때 퍽의 수평(vx)속도를 결정한다. 이 속도는 Cos의 각도와 전체 속도를 사용하여 구한다.
이 경우에 >>8를 사용한 이유는 앞에서 말한것처럼 이 예제에서 고정소수점 연산을 사용하지 않기 위한 것이다. PA_Cos는 고정소수점 값을 반환한다. 그래서 정규수로 다시 변환해야 한다.
속도 이후에 >>8 이 있는 이유는 Cos 후에 올바른 값이 아니기 때문이다. PA_Cos 이후는 정수값이므로 결과는 항상 0이 된다. 속도에 곱했을때에는 나누기전의 전체값은 256보다 많다. 그래서 256으로 나누는 것은(>>8 과 같다) 0으로 결과가 되지 않을 것이다. 픽셀상으로는 더나은 정확한 속도이다.(진짜 속도 2.5는 2가 될것이다.)
같은 방법으로 수직속도도 적용된다. Sin 이기때문에 음수 부호를 가진다.
나머지는 원반 코드와 같고 frisbee를 puck으로 단지 변환한 것이다.
신고
Posted by 버들피리불며

BLOG main image
닌텐도 DS 관련해서 Palib를 소개하고 제가 개발한 홈브류와 다른 개발자의 홈브류를 소개하고자 합니다. NDS 자체 제작(Homebrew)에 관심있는 다른 분들의 길잡이가 되고 싶습니다. by 버들피리불며

공지사항

카테고리

분류 전체보기 (39)
따라하기 (5)
PA_lib 소개 (10)
Homebrew 소개 (7)
나의 Homebrew (15)
기부하기(Donate) (1)
Wii (1)
Total : 105,370
Today : 0 Yesterday : 6