Files
Client/Engine/Zalla3D Scene Class/BoidScene2.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

820 lines
17 KiB
C++

#include "boidscene2.h"
#include "GMMemory.h"
CBoidGroup::CBoidGroup() {
memset(m_BoidName,0,sizeof(char) * 256);
CloseGroup = -1;
Space = LAND;
limit.x = limit.y = limit.z = BOIDUNLIMIT;
SeenRad = SEENDEFAULT;
Pattern = BOIDGROUP;
SubPattern = RELEASE;
FearValue = FEARFULL;
Unit_Num = 0;
Lod = NOT;
Units = NULL;
BoidBox = BOIDRAD;
fwd.x = 1.0f;
fwd.y = 0.0f;
fwd.z = 0.3f;
BoidMesh = NULL;
Boid_Range.x = 0.0f;
Boid_Range.y = 0.0f;
Boid_Range.z = 0.0f;
Boid_Speed = 1.0f;
m_SetPos.x = m_SetPos.y= m_SetPos.z = 0.0f;
srand(time(0));
pat = 0;
m_Pick = false;
m_LimitHeight = 0.0f;
m_CurrentFrame = timeGetTime();
m_BeforeFrame = m_CurrentFrame;
m_BoidKind = 0;
startup = false;
tick = 0;
}
void CBoidGroup::SetBoidName(char *filename,char *path) {
sprintf(m_BoidName,"%s\\%s",path,filename);
}
char *CBoidGroup::GetBoidName() {
return m_BoidName;
}
// 회피 :: 장애물이나 다른 적들과 만나지 않게 회피
void CBoidGroup::avoid()
{
}
//////////////////////////////////////////////////////////////////////////////////////////
// 지형과의 충돌
//회피 :: 지형과의 충돌 회피
void CBoidGroup::HeightSeparate(BoidUnit *boid,D3DXVECTOR3 *vec) {
//////////////////추가되면서 살아나야 한다.
/*
D3DXVECTOR3 field;
D3DXVECTOR3 change;
// 현제 pos 구하기(구현해야함)
//GetHeigh(&field);
//boid 위치 보다 지형이 더 높다면..
if(boid->pos.y < field.y) {
field.y = boid->pos.y;
change = boid->pos - field;
// 위치 복구
boid->pos = boid->before_pos;
D3DXVec3Normalize(&change,&change);
change *=MAX;
(*vec) +=change;
}
*/
}
////////////////////////////////////////////////////////////////////////////////////////
//응집 :: 같은 그룹의 boid 들과 목표 위치를 같게 만들기
void CBoidGroup::concenter(BoidUnit *boid,D3DXVECTOR3 *vec) {
D3DXVECTOR3 div_vec(0.0f,0.0f,0.0f);
float length;
int select_num = 0;
D3DXVECTOR3 tmp(0.0f,0.0f,0.0f);
for(int i=0;i<Unit_Num;i++) {
div_vec = boid->pos - Units[i].pos;
length = D3DXVec3Length(&div_vec);
if(length <BOIDRAD) {
tmp +=Units[i].pos;
select_num++;
}
}
if(select_num) {
tmp /= (float)select_num;
tmp -= boid->pos;
D3DXVec3Normalize(&tmp,&tmp);
tmp *=BMIN;
(*vec) +=tmp;
}
}
void CBoidGroup::SetPos(float x,float y,float z) {
m_SetPos.x = x;
m_SetPos.y = y;
m_SetPos.z = z;
}
// 충돌 피하기 :: 같은 그룹의 boid 들 끼리 부딛히지 않게.
void CBoidGroup::separate(BoidUnit *boid,D3DXVECTOR3 *vec) {
float length;
float r;
int min_index = -1;
float min_length;
D3DXVECTOR3 min_vec(0.0f,0.0f,0.0f);
D3DXVECTOR3 change(0.0f,0.0f,0.0f);
float k = BOIDMAXLIMIT;
D3DXVECTOR3 tmp;
for(int i=0;i<Unit_Num;i++) {
if(boid != (&Units[i])) {
tmp = boid->pos - Units[i].pos;
length = D3DXVec3Length(&tmp);
if(length < k) {
min_index = i;
min_length = length;
min_vec = Units[i].pos;
k = length;
}
}
}
if( min_index == -1 )
return;
// 최소 거리/피하는 범위
r = min_length/(BOIDRAD);
// if(min_length < BOIDRAD) {
change = Units[min_index].pos - boid->pos;
// 너무 작거나 클때 r비율이 (0.05~0.1 사이)
if (r < BMIN)
r = BMIN;
if (r > BMAX)
r = BMAX;
// 충돌 범위 안일때
if (min_length < BOIDRAD) {
D3DXVec3Normalize(&change,&change);
change *=(-0.01f);
//누적
(*vec) +=change;
}
// 충돌 범위 밖일때
else if (min_length> BOIDRAD) {
D3DXVec3Normalize(&change,&change);
change *=0.01f;
//누적
(*vec) +=change;
}
// }
}
//정렬 :: 같은 그룹의 boid 들과 방향벡터를 같게 만들기
void CBoidGroup::align(BoidUnit *boid,D3DXVECTOR3 *vec) {
float k = BOIDMAXLIMIT;
int min_index = -1;
float length;
D3DXVECTOR3 change(0.0f,0.0f,0.0f);
D3DXVECTOR3 tmp(0.0f,0.0f,0.0f);
for(int i=0;i<Unit_Num;i++) {
if(boid != (&Units[i])) {
tmp = boid->pos - Units[i].pos;
length = D3DXVec3Length(&tmp);
if(length < k) {
min_index = i;
k = length;
}
}
}
if(min_index != -1) {
change = Units[min_index].fwd;
D3DXVec3Normalize(&change,&change);
change *=BMIN;
(*vec) +=change;
}
}
void CBoidGroup::RandomRot(CBoidGroup::BoidUnit *boid,float rot) {
static int minus = 1;
int mulyaxis = false;
D3DXVECTOR3 tmp = boid->fwd;
D3DXMATRIX mat;
D3DXMATRIX ver;
D3DXMatrixIdentity(&mat);
D3DXMatrixIdentity(&ver);
ver._41 = tmp.x;
ver._42 = tmp.y;
ver._43 = tmp.z;
minus = minus > 0 ? -1 : 1;
D3DXMatrixRotationY(&mat,D3DXToRadian(rot * (float)minus));
//D3DXMatrixRotationX(&mat,D3DXToRadian(rot * (float)minus));
D3DXMatrixMultiply(&mat,&ver,&mat);
boid->fwd.x = mat._41;
boid->fwd.y = mat._42;
boid->fwd.z = mat._43;
/* do {
if(fabs(boid->fwd.y) < 0.1f)
mulyaxis = true;
else
mulyaxis = false;
boid->fwd.y *=10.0f;
} while(mulyaxis);*/
}
// 경계를 벗어난 boid의 방향 벡터 재 설정
void CBoidGroup::Bound(CBoidGroup::BoidUnit *boid) {
D3DXVECTOR3 tmp = boid->fwd;
D3DXMATRIX mat;
D3DXMATRIX ver;
D3DXMatrixIdentity(&mat);
D3DXMatrixIdentity(&ver);
ver._41 = tmp.x;
ver._42 = tmp.y;
ver._43 = tmp.z;
switch(m_BoidKind) {
case 0:
D3DXMatrixRotationY(&mat,D3DXToRadian(2.0f));
break;
case 1:
D3DXMatrixRotationY(&mat,D3DXToRadian(15.0f));
break;
}
D3DXMatrixMultiply(&mat,&ver,&mat);
//float tmp;
float size_x = Boid_Range.x;
float size_z= Boid_Range.z;
// 방향을 바꾸지 않은 상태
if(((boid->pos.x - m_SetPos.x) > size_x) || ((m_SetPos.x - boid->pos.x) > size_x)) {
// tmp = (boid->fwd.x) * (-0.4f);
// boid->fwd.x -= tmp;
boid->fwd.x = mat._41;
boid->fwd.y = mat._42;
boid->fwd.z = mat._43;
}
if(((boid->pos.z - m_SetPos.z) > size_z) || ((m_SetPos.z - boid->pos.z) > size_z)) {
// tmp = (boid->fwd.z) * (-0.4f);
// boid->fwd.z -=tmp;
boid->fwd.x = mat._41;
boid->fwd.y = mat._42;
boid->fwd.z = mat._43;
}
/*
if(boid->pos.x <(float)(TEST_SECNUM * TEST_SECSIZE))
boid->pos.x = ((float)(TEST_SECNUM * TEST_SECSIZE) + TEST_SECSIZE);
else if(boid->pos.x >((float)(TEST_SECNUM * TEST_SECSIZE) + TEST_SECSIZE))
boid->pos.x = (float)(TEST_SECNUM * TEST_SECSIZE);
if(boid->pos.y <(float)(TEST_SECNUM * TEST_SECSIZE))
boid->pos.y = ((float)(TEST_SECNUM * TEST_SECSIZE) + TEST_SECSIZE);
else if(boid->pos.y >((float)(TEST_SECNUM * TEST_SECSIZE) + TEST_SECSIZE))
boid->pos.y = (float)(TEST_SECNUM * TEST_SECSIZE);
if(boid->pos.z <(float)(TEST_SECNUM * TEST_SECSIZE))
boid->pos.z = ((float)(TEST_SECNUM * TEST_SECSIZE) + TEST_SECSIZE);
else if(boid->pos.z >((float)(TEST_SECNUM * TEST_SECSIZE) + TEST_SECSIZE))
boid->pos.z = (float)(TEST_SECNUM * TEST_SECSIZE);
*/
}
CBoidGroup::~CBoidGroup() {
if(Unit_Num || (Units != NULL)) {
delete[] Units;
Units = NULL;
}
/* if(BoidMesh)
delete BoidMesh;*/
}
void CBoidGroup::SetUnitNum(int n) {
Unit_Num = n;
Units = new BoidUnit[Unit_Num];
SetUnit();
}
//최종 단계 rot
void CBoidGroup::RotSet(CBoidGroup::BoidUnit *U) {
float roll, pitch, yaw;
float lateDot;
D3DXVECTOR3 late,tmp;
D3DXVECTOR3 tmp2;
// stop 상태
if(U->fwd == U->before_fwd)
return;
tmp = U->fwd - U->before_fwd;
D3DXVec3Cross(&tmp2,&U->fwd,&tmp);
D3DXVec3Cross(&late,&tmp2,&U->fwd);
D3DXVec3Normalize(&late,&late);
lateDot = D3DXVec3Dot(&tmp,&late);
if (lateDot == 0) {
roll = 0.0f;
}
else {
roll = (float) -atan2(BGRAVITY, lateDot) + BHALF_PI;
}
pitch = (float) -atan(U->fwd.y / sqrt((U->fwd.z * U->fwd.z ) + (U->fwd.x * U->fwd.x)));
yaw = (float) atan2(U->fwd.x, U->fwd.z);
U->rot[0] = pitch;
U->rot[1] = yaw;
U->rot[2] = roll;
}
void CBoidGroup::SetFwd() {
int i;
for(i=0;i<Unit_Num;i++) {
Units[i].fwd.x = BRAND();
Units[i].fwd.y = BRAND();
Units[i].fwd.z = BRAND();
if(rand()%2)
Units[i].fwd.x *=-1.0f;
if(rand()%2)
Units[i].fwd.y *=-1.0f;
if(rand()%2)
Units[i].fwd.z *=-1.0f;
if(rand()%2) {
//Units[i].fwd.x = Units[i].fwd.y = Units[i].fwd.z = 0.0f;
//Units[i].before_fwd.x = Units[i].before_fwd.y = Units[i].before_fwd.z = 0.0f;
}
//fwd length
Units[i].speed = D3DXVec3Length(&Units[i].fwd);
}
}
void CBoidGroup::separate2(BoidUnit *boid) {
int i;
D3DXVECTOR3 tmp;
D3DXVECTOR3 tf;
float length;
D3DXVECTOR3 min_vec;
int min_index;
float k = BOIDMAXLIMIT;
for(i=0;i<Unit_Num;i++) {
if(boid != (&Units[i])) {
tmp = boid->pos - Units[i].pos;
length = D3DXVec3Length(&tmp);
if(length < k) {
min_vec = tmp;
min_index = i;
k= length;
}
}
}
if(k < BOIDRAD) {
D3DXVec3Normalize(&min_vec,&min_vec);
D3DXVec3Normalize(&tf,&boid->fwd);
tmp = tf + min_vec;
//튕기기
tmp *=BMIN;
boid->fwd += tmp;
}
}
void CBoidGroup::Update() {
int i,j,count;
if(startup == false) {
m_CurrentFrame = timeGetTime();
m_BeforeFrame = m_CurrentFrame;
startup = true;
}
m_CurrentFrame = timeGetTime();
count = (int)(m_CurrentFrame - m_BeforeFrame)/30;
for(j=0;j<count;j++) {
m_CurrentFrame = timeGetTime();
m_BeforeFrame = m_CurrentFrame;
D3DXVECTOR3 change(0.0f,0.0f,0.0f);
if(!(tick % 35))
pat = (pat >0) ? 0:1;
tick++;
//pat = 1;
for(i=0;i<Unit_Num;i++) {
Units[i].frame+=(Units[i].vot);
if((Units[i].frame * BoidMesh->m_UnitF) >= BoidMesh->m_EndF) {
float kvalue = (float)((float)(Units[i].frame * BoidMesh->m_UnitF) / BoidMesh->m_EndF);
Units[i].frame = (Units[i].frame * BoidMesh->m_UnitF) - (BoidMesh->m_EndF * kvalue);
Units[i].frame /= (float)BoidMesh->m_UnitF;
if(Units[i].frame <= 0.0f)
Units[i].frame = 0.0f;
//Units[i].vot = Units[i].backup_vot;
}
/* if((Units[i].frame * BoidMesh->m_UnitF) >= BoidMesh->m_EndF) {
Units[i].frame = (BoidMesh->m_StartF / BoidMesh->m_UnitF);
Units[i].vot = Units[i].backup_vot;
}
*/
// if(Units[i].active != SLEEP) {
Units[i].before_pos = Units[i].pos;
Units[i].before_fwd = Units[i].fwd;
Units[i].pos +=(Units[i].fwd);
// 집단 행동 설정시
if(pat) {
// 같은 group의 boid 들 끼리의 충돌 방지(기본 반지름 2.0f)
// 흔들림이 있어서 BOIDRAD 안의 것들만 적용되게 해놓았음
separate(&Units[i],&change);
// 옆의 boid 와 방향을 비슷 하게 만든다
align(&Units[i],&change);
//응집 :: 같은 그룹의 boid 들과 목표 위치를 같게 만들기
concenter(&Units[i],&change);
randomvec(&Units[i],&change);
//계산되어진 결과 추가
if(D3DXVec3Length(&change) > BMAXCHANGE) {
D3DXVec3Normalize(&change,&change);
change *=BMAXCHANGE;
}
}
else {
separate2(&Units[i]);
}
// 지형과의 높이 체크
//HeightSeparate(&Units[i],&change);
Units[i].fwd +=change;
// 흔들림 조절 (y 축 값 조정)
Units[i].fwd.y *= 0.4f;
//butterfly(Units[i]);
//speed 조절 (1.0)이하로
if ((Units[i].speed = D3DXVec3Length(&Units[i].fwd)) > BMAXSPEED) {
D3DXVec3Normalize(&Units[i].fwd,&Units[i].fwd);
Units[i].fwd *=(BMAXSPEED);
Units[i].speed = BMAXSPEED;
}
// 속도 조절
(Units[i].fwd) *= Boid_Speed;
switch(m_BoidKind) {
case 0:
break;
case 1:
if(!(tick % (30 /*+ (15 - (int)Boid_Speed)*/)))
RandomRot(&Units[i],25.0f);
break;
}
// 방향의 지그재그 적용
// 나비 일때 로 세팅 중
// 속도가 15일때 20 프레임에 한번씩 업데이트
Bound(&Units[i]);
RotSet(&Units[i]);
// 경계 박스와의 충돌시 방향 벡터 수정
/* if(!pat) {
//테스트 Land live
if(Units[i].height<0)
Units[i].pos.y++;
else if(Units[i].height>0) {
Units[i].pos.y--;
}
if(Units[i].pos.y == 500 || Units[i].pos.y == 0)
Units[i].height *= (-1);
}*/
// }
}
}
}
void CBoidGroup::randomvec(BoidUnit *boid,D3DXVECTOR3 *vec) {
/*
D3DXVECTOR3 tmp(0.0f,0.0f,0.0f);
float diff = (boid->speed - 0.05f)/ MAX;
float urgency = (float) fabs(diff);
if (urgency < MIN) urgency = MIN;
if (urgency > MAX) urgency = MAX;
float jitter = RAND();
if (jitter < 0.45f) {
vec->x += MIN * SIGN(diff);
} else if (jitter < 0.90f) {
vec->z += MIN * SIGN(diff);
} else {
vec->y += MIN * SIGN(diff);
}
if(rand() %2)
(*vec) *= -0.001;
else
(*vec) *= 0.001;
//if(rand() %10 == 7)
/* if(rand() %2) {
tmp.x = rand()%10 -5;
tmp.y = rand()%10 -5;
tmp.z = rand()%10 -5;
(*vec) += tmp;
// if(rand() %2)
// boid->fwd.x = boid->fwd.y = boid->fwd.z = 0.0f;
}*/
}
void CBoidGroup::SetUnitVot(float vot) {
for(int i=0;i<Unit_Num;i++) {
Units[i].vot = vot;
Units[i].backup_vot = vot;
}
}
void CBoidGroup::SetUnit() {
int i;
// boid 별 시작프레임 set
float last_frame = (float)((float)BoidMesh->m_EndF / BoidMesh->m_UnitF);
float frame_set[6] = {0.0f,
last_frame * (1.0f/5.0f),
last_frame * (2.0f/5.0f),
last_frame * (3.0f/5.0f),
last_frame * (4.0f/5.0f),
last_frame * (5.0f/5.0f),
};
//SECTORSIZE
for(i=0;i<Unit_Num;i++) {
Units[i].rot[0] = Units[i].rot[1] = Units[i].rot[2] = 0.0f;
// pos
Units[i].pos.x = m_SetPos.x + (float)(rand()%(int)Boid_Range.x);
Units[i].pos.y = m_SetPos.y + (float)(rand()%(int)Boid_Range.y);
Units[i].pos.z = m_SetPos.z + (float)(rand()%(int)Boid_Range.z);
if(Units[i].pos.y < m_SetPos.y + m_LimitHeight) { // 최저 높이 세팅
Units[i].pos.y = m_SetPos.y + m_LimitHeight;
}
// live
Units[i].Live = true;
Units[i].active = rand()%5;
Units[i].fwd.x = BRAND();
Units[i].fwd.y = BRAND();
Units[i].fwd.z = BRAND();
Units[i].height = -1;
if(rand()%2)
Units[i].fwd.x *=-1.0f;
if(rand()%2)
Units[i].fwd.y *=-1.0f;
if(rand()%2)
Units[i].fwd.z *=-1.0f;
//fwd length
Units[i].speed = D3DXVec3Length(&Units[i].fwd);
Units[i].vot = 1.0f;
Units[i].frame = frame_set[(rand() % 6)];
Units[i].backup_frame = Units[i].frame;
//BoidMesh->SetVot(Units[i].vot);
/* //speed
switch(SubPattern) {
case RELEASE:
//Units[i].fwd.x = 0.1f;
//Units[i].fwd.y = 0.0f;
//Units[i].fwd.z = 1.0f;
break;
case AVOID:
Units[i].fwd.x = fwd.x + (float)(rand()%1000)/1000.0f - 0.5f;
Units[i].fwd.y = fwd.y + (float)(rand()%1000)/1000.0f - 0.5f;
Units[i].fwd.z = fwd.z + (float)(rand()%1000)/1000.0f - 0.5f;
break;
}
switch(Units[i].active) {
case SLEEP:
Units[i].fwd.x = Units[i].fwd.y = Units[i].fwd.z =0.0f;
break;
case PEACE:
Units[i].fwd.x = (float)(rand()%1000)/1000.0f - 0.5f;
Units[i].fwd.y = 0.0f;//(float)(rand()%1000)/1000.0f - 0.5f;
Units[i].fwd.z = (float)(rand()%1000)/1000.0f - 0.5f;
Units[i].fwd *= 0.1f;
break;
case WALK:
Units[i].fwd.x = fwd.x;
Units[i].fwd.y = 0.0f;//fwd.y;
Units[i].fwd.z = fwd.z;
Units[i].fwd *=0.01f;
break;
case RUN:
Units[i].fwd.x = fwd.x;
Units[i].fwd.y = 0.0f;//fwd.y;
Units[i].fwd.z = fwd.z;
break;
case FLYING:
Units[i].fwd.x = fwd.x;
Units[i].fwd.y = fwd.y;
Units[i].fwd.z = fwd.z;
break;
}
*/
switch(Space) {
case LAND:
// Units[i].pos.y = GetHeight(Units[i].pos.x,Units[i].pos.z);
// Units[i].speed.y = 0.0f;
// Units[i].pos.y = 0.0f;
// Units[i].pos.y = 0.0f;
// Units[i].fwd.y = 0.0f;
break;
case WATER:
break;
case FLY:
break;
}
}
}
void CBoidGroup::butterfly(CBoidGroup::BoidUnit &Unit){
//나비의 y축 움직임
// Unit.fwd.y += 0.3f;
if(Unit.m_fly<100) {
Unit.pos.y += 1.0f;
Unit.m_fly++;
}
else if(Unit.m_fly >=100 && Unit.m_fly <=200){
Unit.pos.y -= 1.0f;
Unit.m_fly++;
}
else if(Unit.m_fly >200){
Unit.m_fly = 0;
}
}
bool CBoidGroup::Render(LPDIRECT3DDEVICE8 device) {
D3DXMATRIX world;
device->GetTransform(D3DTS_WORLD,&world);
D3DXMATRIX back = world;
D3DXMATRIX quater;
D3DXQUATERNION qt;
int i;
D3DXMatrixIdentity(&quater);
int lod = 0;
switch(lod) {
case NOT:
for(i=0;i<Unit_Num;i++) {
world = back;
D3DXQuaternionRotationYawPitchRoll(&qt,Units[i].rot[1],Units[i].rot[0],Units[i].rot[2]);
D3DXMatrixRotationQuaternion(&world,&qt);
world._41 = Units[i].pos.x;
world._42 = Units[i].pos.y;
world._43 = Units[i].pos.z;
if(strstr(m_BoidName,"Boid_Gull_T1.GEM") != NULL)
world._42 += 1500.0f;
BoidMesh->SetTransMatrix(world);
/*if((Units[i].frame * BoidMesh->m_UnitF) >= BoidMesh->m_EndF) {
float kvalue = (float)((float)(Units[i].frame * BoidMesh->m_UnitF) / BoidMesh->m_EndF);
Units[i].frame = (Units[i].frame * BoidMesh->m_UnitF) - (BoidMesh->m_EndF * kvalue);
Units[i].frame /= (float)BoidMesh->m_UnitF;
if(Units[i].frame <= 0.0f)
Units[i].frame = 0.0f;
//Units[i].vot = Units[i].backup_vot;
}
*/
/*
if((Units[i].frame * BoidMesh->m_UnitF) >= BoidMesh->m_EndF) {
//Units[i].frame = (BoidMesh->m_StartF / BoidMesh->m_UnitF);
Units[i].frame = (int)(Units[i].frame * BoidMesh->m_UnitF) % (int)BoidMesh->m_EndF;
if(Units[i].frame <= 0.0f)
Units[i].frame = 0.0f;
else
Units[i].frame /= (float)BoidMesh->m_UnitF;
Units[i].vot = Units[i].backup_vot;
}
*/
//BOID 마다 플레이 프레임 다르게
BoidMesh->SetCurrentFrame(Units[i].frame);
BoidMesh->SetBlend(D3DBLEND_ONE,D3DBLEND_ZERO);
BoidMesh->SetNullTexture(m_Pick);
BoidMesh->Render();
//Update();
//BoidMesh->Update();
}
break;
case MIDDLE:
break;
}
return true;
}