'전체보기'에 해당되는 글 133건

  1. 2012.10.25 도트 이미지 - setgalefreeus
  2. 2012.10.25 pushpush
  3. 2012.09.13 a* 알고리즘
  4. 2012.09.06 사인 코사인 탄젠트
  5. 2012.08.26 asciiexp
  6. 2012.08.24 울트라 iso
  7. 2012.08.21 한국의 귀신 신령 요괴
  8. 2012.08.16 .hack 이미지
  9. 2012.08.16 4leaf 클라이언트
  10. 2012.08.10 Intersection of a Line and
posted by Junction 2012. 10. 25. 14:21

setgalefreeus

 

도트 이미지

에디터

 

setgalefreeus.exe

'Data' 카테고리의 다른 글

갓 이터 버스트( GEB ) - Drama & Original Soundtrack  (0) 2012.11.10
tap control  (0) 2012.11.04
pushpush  (0) 2012.10.25
asciiexp  (0) 2012.08.26
울트라 iso  (0) 2012.08.24
posted by Junction 2012. 10. 25. 13:53

푸시 푸시.

 

 

푸시 푸시 ㅜ.ㅜ

 

 

ProjectG_PushPush.zip

 

pushpush.zip

'Data' 카테고리의 다른 글

tap control  (0) 2012.11.04
도트 이미지 - setgalefreeus  (0) 2012.10.25
asciiexp  (0) 2012.08.26
울트라 iso  (0) 2012.08.24
4leaf 클라이언트  (0) 2012.08.16
posted by Junction 2012. 9. 13. 09:52

그리고 이 흰색 화살표의 노드들을 역으로 추적하면 결국 최단거리가 나오는 것이지요. 물론 흰색 노드는 ClosedNode에 포함된 노드들이며 최종적으로 목적지에 도달했을 때의 노드를 역으로 추적하면 되는 겁니다.

어때요.. 참 쉽죠잉? (아 힘들어.. 이거야 말로 충격과 공포 ㅡㅜ)

자, 이론은 이해하셨을 거라고 믿고... 이제 구현 한번 들어가 보도록 하겠습니다.

//노드에 대한 정의

typedef struct node_s {
int degree;
//현재 이 노드의 깊이 값. 즉, 자료 구조 트리에서 깊이 값.

int distance; //이 노드로부터 목적지까지의 거리

int value_factor; //평가치 값( degree + distance )

int x, y; //이 노드의 위치 (그리드의 위치)
struct node_s* direct[8]; //확장 가능한 8방향에 대한 노드
struct noder_s* prev_node; //링크드 리스트 이전 노드
struct node_s* next_node; //링크드 리스트 다음 노드
} node_t;

//노드를 재정렬할 때 쓸 스택.

typedef struct node_stack_s {
node_t* node; //이 스택 위치에서 가리키고 있는 노드
struct node_stack_s* next_node; //이 스택의 다음 위치
} node_stack_t;

참고로 평가치 값은 degree + distance로 구하는데 거리와 degree의 값의 단위는 해당 프로그램에 맞게 적절하게 정하시면 될 것 같습니다. (degree간의 값의 차이가 1이라고 본다면 인접한 노드들 간의 거리도 1로 지정하는게 적절할 것 같습니다.)

그리고, OPEN_NODE와 CLOSE_NODE 그리고 스택을 위한 전역 데이터를 각각 선언합니다.

node_t *OPEN = NULL, *CLOSED = NULL;

node_stack_t* STACK = NULL;

다음 함수들은 구현하기에 어렵지도 않고 중요하지도 않으니 간단한 주석 설명으로 대처 하였습니다.

//리스트와 스택을 초기화 또는 제거 해주는 함수

void init_astar()

{

//OPEN노드를 순회하면서 각 노드를 제거

//CLOSE노드를 순회하면서 각 노드를 제거

//스택을 순회하면서 각 스택에 존재하는 데이터 제거, 스택 공간 제거

}

//해당 그리드로 이동 가능한지 판단하는 함수

bool is_available_grid( int x, int y )

{

//캐릭터가 어떤 그리드로 이동하기 전에 그 그리드가 이동가능한지 여부를 판단하는 부분을 구현합니다.

//상황에 따라 다르므로 역시 의사코드.

//이동 가능한 그리드면 TRUE

//블럭된 것과 같이 이동 불가능한 그리드면 FALSE

}

//해당 위치의 노드가 OPEN NODE에 존재하는 지 파악하는 함수

node_t* is_open( int x, int y )

{

//OpenNode를 순회하면서 입력한 위치 값의 노드가 존재하는 지 파악.

//존재하면 해당 노드를 반환

}

//해당 위치의 노드가 CLOSED NODE에 존재하는 지 파악하는 함수

node_t* is_closed( int x, int y )

{

//ClosedNode를 순회하면서 입력한 위치 값의 노드가 존재하는지 파악.

//존재하면 해당 노드를 반환

}

//해당 노드를 스택 공간에 삽입하는 함수

void push_into_stack( node_t* node )

{

//스택 공간 할당

//생성한 스택 공간에 삽입할 노드를 지정

//기존 스택에 생성한 스택 공간을 연결

}

//해당 노드를 스택 공간에 삽입하는 함수

node_t* pop_from_stack()

{

//스택 공간에서 노드 데이터 꺼내옴

//해당 스택 공간 삭제

//노드 반환

}

물론 위의 의사코드 부분은 첨부파일에 완성되어 있으니 참고하시기 바랍니다.

자, 이제부터 좀 중요한 부분들을 보도록 하죠. 먼저 길찾기 시작 함수입니다.

//출발점 x,y, 목적지 x,y

node_t* find_path( int start_x, int start_y, int dest_x, int dest_y ) {

node_t* present=NULL; //출발점 노드

//시작 위치 노드 추가. 여기서는 시작 위치가 목적지가 되겠습니다. 즉, 목적지에서 -> 출발지 방향으로 탐색.

//위의 그림설명에서 완성된 노드가 역으로 연결된 점을 확인하셨다면, 목적지->출발지로 하면 되겠죠.
present = ( node_t* ) calloc( 1, sizeof(node_t) );
present->degree = 0;
present->distance= pow( (dest_x- start_x ), 2 ) + pow( (dest_y - start_y ), 2 );
//진정한 의미에서는 루트를 씌워야

//겠지만 구지 안씌워도 문제될 건 없죠.
present->value_factor = present->distance; // distance + degree
present->x= dest_x;
present->y= dest_y;

OPEN=present;

node_t* best=NULL; //best는 현재까지 최적의 경로에 대한 리스트입니다.
int count=0; //탐색 깊이 값을 카운팅 합니다. 무한 루프에 빠질 가능성을 제한할 용도이죠.

//탐색 시작합니다. 길 찾기를 실패할 경우에 대비해서 루프문에 제한을 둘 필요가 있습니다.

while(count< FINDPATH_LIMIT) {

//모든 노드에 대한 찾기를 수행했을 경우. 그럴 경우 아마 최적의 길을 찾았겠죠? 아마..

if(OPEN==NULL) {
return best;

}

best = OPEN; //매 루프문을 돌면서 OpenNode의 후보로부터 탐색을 우선 시도합니다.
OPEN = best->next_node; //그리고 그 다음 노드가 OpenNode의 최상위 후보노드로 지정되며
best->next_node = CLOSED; //지금까지 구축된 최적의 노드를 이번에 탐색할 best노드와 연결함으로써

//현재까지 탐색된 최적의 길을 유지하게 됩니다.
CLOSED=best; //이 best노드는 이번 루프에서 탐색 시도되므로 close노드로 들어가게 되는거죠.

//길찾기 실패

if(best==NULL) {
return NULL;

}

//길찾기 성공
if(best->x == start_x && best->y == start_y )
return best;

//현재 탐색 노드를 중심으로 8방향으로 확장.
if(make_child(best, start_x, start_y )==0 && count ==0)
return NULL;

count++;

}

return best;

}

자 다음으로, 현재 탐색 노드를 확장하는 함수를 보도록 합시다.

//현재 탐색할 노드, 목적지 x, y, 반환값은 현 노드의 확장 여부

bool make_child( node_t* node, int dest_x, int dest_y ) {


bool extended = false; //하나라도 확장된 사실이 있으면 true
int x = node->x;
int y = node->y;

//각 8방향에 대해 이동 가능한 지역에 대해서 자식 노드 생성

//왼편.
if( is_available_grid( x - 1, y ) ) {
extend_child_node( node, x-1, y, dest_x, dest_y, LEFT_IDX );
extended=1;
}

//그 외 7방향에 대해서는 해당 x, y값을 주어서 똑같이 호출하면 되겠습니다.

//여기서는 생략.

//오른편 x + 1, y

//상단 x, y - 1

//하단 x, y + 1

//좌측 상단 x - 1, y - 1

//우측 상단 x + 1, y - 1

//좌측 하단 x - 1, y + 1

//우측 하단 x + 1, y + 1

return extened;

}

여기까지는 이해가 되셨길 합니다. 사실 위의 예에서 보여준 게임같은 경우, 대각선 이동은 인접한 두 그리드가 이동 가능할 때 허용되도록 컨셉을 잡는게 더 현실적일 겁니다. 따라서 대각선 판단은 인접한 두 노드가 이동 가능할 때 판단하면 될 듯 합니다. 그건 직접 수정 가능하시겠죠? :)

-인접한 두 노드의 블럭 상태로 대각선 이동 안됨-

자, 다음 함수를 보도록 합시다. 이번 함수는 노드를 확장하고 필요한 경우 리스트를 재정렬합니다.

//확장할 노드, 현재 노드 위치, 목적지 위치, 확장할 방향 인덱스

void extend_child_node( node_t* node, int cur_x, int cur_y, int dest_x, int dest_y, int cur_direct ) {

node_t *old = NULL, *child = NULL;
int i;
int degree= node->degree+1;

//확장할 노드가 OpenNode에 존재한다면,
if( old = Is_open( cur_x, cur_y ) ) {

node->direct[ cur_direct ] = old;

//그리고 노드 재연결 및 설정 . 참고로 노드 방향이 반대로 적용된다는 걸 고려할 것.
if( degree < old->degree ) {
old->prev_node = node;
old->degree = degree;
old->value_factor = old->distance + old->degree;
}

//확장할 노드가 CloseNode에 존재한다면,

}else if( old = is_close( cur_x, cur_y ) ) {

node->direct[ cur_direct ] = old;

//어떤 경우에는 기존 CloseNode에 있는 노드의 degree가 더 적을 경우가 발생할 수도 있는데

//이 때 순서를 다시 설정
if(degree<old->degree) {
old->prev_node = node;
old->degree = degree;
old->value_factor = old->distance + old->degree;
make_sort( old );
}

//확장할 노드 생성 및 OpenNode 리스트에 추가

}else {

if( ( child = ( node_t* ) calloc( 1, sizeof( node_t ) ) ) == NULL )
return; //lack of memory

child->prev_node = node;
child->degree = degree;
child->distance = ( cur_x - dest_x ) * ( cur_x - dest_x ) + ( cur_y - dest_y ) * ( cur_y - dest_y );
child->value_factor = child->distance + child->degree;
child->x = cur_x;
child->y = cur_y;

Insert_node_( child );

node->direct[ cur_direct ] = child;

}

}

이제 좀 머리가 아파오실 수도 있습니다. 본 내용과 소스만으로 이해가 되지 않는다면 직접 가상의 길을 그린 후에 이 알고리즘을 따라 직접 확장해 보시는걸 추천드립니다. 그러면 확실해지겠죠.

//재평가힐 노드의 기준

void make_sort( node_t* old ) {

node_t *direct, *previous;
int i;
int degree = old->degree+1;

for(i=0; i<8; i++) {

if( ( direct = old->direct[i] ) == NULL )
continue;

//순서 재정렬로 인한 연결된 노드들의 설정값이 얽힌경우 재설정을 해줍니다.

//자식 노들들을 위해 스택 공간을 이용합니다.

if( direct->degree > degree ) {
direct->prev_node = old;
direct->degree = degree;
direct->value_factor = direct->distance + direct->degree;

push_into_stack( direct );
}

}

//스택 공간을 이용하여 차례차레 노드들을 재 설정.

while( STACK ) {

previous = pop_from_stack();

for( i=0; i<8; i++ ) {

if( ( direct = previous->direct[i]) == NULL )
break;

if( direct->degree > previous->degree + 1 ) {
direct->prev_node = previous;
direct->degree = previous->degree + 1;
direct->value_factor = direct->distance + direct->degree;

push_into_stack( direct );
}
}
}

}

주석 설명이 다소 부진할 수 있을지도 모르겠습니다. 예제의 경우에 나타나지 않았던 예외적인 상황에 대한 처리부분이지요. 이 부분은 CloseNode의 순서가 바뀌면서 그에 따른 연결된 노드들을 재평가합니다.

마지막으로 노드를 OpenNode에 추가합니다. 주석 내용이 번잡하게 들릴 수도 있는데 결국은, 노드 삽입 시 목적지에 가까운 순서를 유지 한다는 점.

//확장한 새 노드

void Insert_node( node_t* present ) {

node_t* old = NULL, *temp = NULL;

if(OPEN == NULL) {
OPEN = present;
return;
}

temp=OPEN;

//OpenNode에 있는 노드가 현재 자식 노드보다 평가치가 낮으면
//OpenNode를 추적해서 현재 자식 노드보다 평가치가 높은 노드를 찾는다.
while(temp && (temp->value_factor < present->value_factor ) ) {
old=temp;
temp=temp->next_node;
}


//낮은 평가치의 OpenNode 중 출발지에 가장 가까운 노드 -> 추가할 자식 노드 -> 높은 평가치의 OpenNode 중 출발지에 가

//장 먼 노드
if(old) {
present->next_node = temp;
old->next_node = present;
}else {
present->next_node = temp;
OPEN = present;
}

}

제 역량 부족으로 설명이 힘들군요. 이중 연결 리스트 2개와 스택이 서로 얽혀있어서 말로는 다소 이해하기 힘들 수도 있구요.

예제 소스를 활용하여 진행 노드 상황을 직접 표현하여 이해해보는 것이 명확할 듯 합니다. ㅎㅎ (이런 무책임한...)

자, 어쨌든 A*에 대한 설명은 여기서 마치렵니다. 사실 최적화 방안은 여러 존재합니다. 예를 들면 직선 이동 노드들에 대해선 생략을 한다던지, 맵에 대한 WayPoint 정보를 추가로 삽입하여 이를 토대로 길찾기를 수행한다든지.. 적어도 위 게임에서 문에 대한 위치 정보를 참고할 수만 있어도 매우 최적화된 탐색이 수행되겠지요.

또한 3D 공간에 대해서는 다소 데이터 자체가 매우 상이할 겁니다. (추가적인 정보는 Game Programming Gems 1권을 추천합니다.)

부족한 설명은 첨부 소스를 참고하여 보충하시기 바랍니다.

posted by Junction 2012. 9. 6. 19:10

 

'잡동사니' 카테고리의 다른 글

인테리어 목공 - 가벽.  (0) 2017.05.31
인테리어 목공- 천장  (0) 2017.05.31
.hack 이미지  (0) 2012.08.16
posted by Junction 2012. 8. 26. 10:31

 

asciiexp.rar

 

3d max 2009 와우 모델 ASE파일로 추출시 내 스타일.

'Data' 카테고리의 다른 글

tap control  (0) 2012.11.04
도트 이미지 - setgalefreeus  (0) 2012.10.25
pushpush  (0) 2012.10.25
울트라 iso  (0) 2012.08.24
4leaf 클라이언트  (0) 2012.08.16
posted by Junction 2012. 8. 24. 11:26

 

UltraISOPortable.zip

'Data' 카테고리의 다른 글

tap control  (0) 2012.11.04
도트 이미지 - setgalefreeus  (0) 2012.10.25
pushpush  (0) 2012.10.25
asciiexp  (0) 2012.08.26
4leaf 클라이언트  (0) 2012.08.16
posted by Junction 2012. 8. 21. 10:35

posted by Junction 2012. 8. 16. 11:58

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'잡동사니' 카테고리의 다른 글

인테리어 목공 - 가벽.  (0) 2017.05.31
인테리어 목공- 천장  (0) 2017.05.31
사인 코사인 탄젠트  (0) 2012.09.06
posted by Junction 2012. 8. 16. 11:55

 

4Leaf096d.part1.rar

 

4Leaf096d.part2.rar

 

4Leaf096d.part3.rar

 

4Leaf096d.part4.rar

 

4Leaf096d.part5.rar

 

4Leaf096d.part6.rar

 

4Leaf096d.part7.rar

소프트 맥스 4leaf 클라이언트 구버전.

'Data' 카테고리의 다른 글

tap control  (0) 2012.11.04
도트 이미지 - setgalefreeus  (0) 2012.10.25
pushpush  (0) 2012.10.25
asciiexp  (0) 2012.08.26
울트라 iso  (0) 2012.08.24
posted by Junction 2012. 8. 10. 15:38

Points P (x,y) on a line defined by two points P1 (x1,y1,z1) and P2 (x2,y2,z2) is described by

P = P1 + u (P2 - P1)

or in each coordinate

x = x1 + u (x2 - x1)
y = y1 + u (y2 - y1)
z = z1 + u (z2 - z1)

A sphere centered at P3 (x3,y3,z3) with radius r is described by

(x - x3)2 + (y - y3)2 + (z - z3)2 = r2

Substituting the equation of the line into the sphere gives a quadratic equation of the form

a u2 + b u + c = 0

where:

a = (x2 - x1)2 + (y2 - y1)2 + (z2 - z1)2

b = 2[ (x2 - x1) (x1 - x3) + (y2 - y1) (y1 - y3) + (z2 - z1) (z1 - z3) ]

c = x32 + y32 + z32 + x12 + y12 + z12 - 2[x3 x1 + y3 y1 + z3 z1] - r2

The solutions to this quadratic are described by

The exact behaviour is determined by the expression within the square root

b * b - 4 * a * c

  • If this is less than 0 then the line does not intersect the sphere.

  • If it equals 0 then the line is a tangent to the sphere intersecting it at one point, namely at u = -b/2a.

  • If it is greater then 0 the line intersects the sphere at two points.

To apply this to two dimensions, that is, the intersection of a line and a circle simply remove the z component from the above mathematics.

Line Segment

For a line segment between P1 and P2 there are 5 cases to consider.

  • Line segment doesn't intersect and on outside of sphere, in which case both values of u wll either be less than 0 or greater than 1.

  • Line segment doesn't intersect and is inside sphere, in which case one value of u will be negative and the other greater than 1.

  • Line segment intersects at one point, in which case one value of u will be between 0 and 1 and the other not.

  • Line segment intersects at two points, in which case both values of u will be between 0 and 1.

  • Line segment is tangential to the sphere, in which case both values of u will be the same and between 0 and 1.

When dealing with a line segment it may be more efficient to first determine whether the line actually intersects the sphere or circle. This is achieved by noting that the closest point on the line through P1P2 to the point P3 is along a perpendicular from P3 to the line. In other words if P is the closest point on the line then

(P3 - P) dot (P2 - P1) = 0

Substituting the equation of the line into this

[P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0

Solving the above for u =

(x3 - x1)(x2 - x1) + (y3 - y1)(y2 - y1) + (z3 - z1)(z2 - z1)
-----------------------------------------------------------
(x2 - x1)(x2 - x1) + (y2 - y1)(y2 - y1) + (z2 - z1)(z2 - z1)

If u is not between 0 and 1 then the closest point is not between P1 and P2 Given u, the intersection point can be found, it must also be less than the radius r. If these two tests succeed then the earlier calculation of the actual intersection point can be applied.