www.pudn.com > mmxswarm.zip > Swarm.cpp
// Swarm.cpp : implementation of the CSwarm class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
//
#include "stdafx.h"
#include "Swarm.h"
COLORREF CBrightLeader::m_sColorTable[256] = { 0 };
///////////////////////////////////////////////////////////////////////
// Swarm
CSwarm::CSwarm() :
m_pSurf(NULL)
{
}
CSwarm::~CSwarm()
{
Destroy();
}
void CSwarm::Destroy()
{
for (size_t i = 0; i < m_LeaderArr.GetCount(); i++)
delete m_LeaderArr[i];
for (size_t i = 0; i < m_LlamaArr.GetCount(); i++)
delete m_LlamaArr[i];
m_LeaderArr.SetCount(0);
m_LlamaArr.SetCount(0);
m_pSurf = NULL;
}
void CSwarm::Initialize(CSurface *pSurf, int nLeaders, int nLlamas, const CSize &size)
{
Destroy();
m_nWidth = size.cx;
m_nHeight = size.cy;
if (!m_nHeight || !m_nWidth)
return;
m_pSurf = pSurf;
m_nAge = 0;
m_nBorder = (m_nWidth + m_nHeight) / 50;
m_LeaderArr.SetCount(nLeaders);
m_LlamaArr.SetCount(nLlamas);
for (int i = 0; i < nLeaders; i++) {
m_LeaderArr[i] = GetLeader();
}
for (int i = 0; i < nLlamas; i++) {
m_LlamaArr[i] = new CLlama();
m_LlamaArr[i]->Init(this);
}
}
CLeader *CSwarm::GetLeader()
{
CLeader *pLeader = NULL;
switch (Random(2)) {
case 0:
pLeader = new CBrightLeader();
break;
case 1:
pLeader = new CHueLeader();
break;
}
ASSERT(pLeader != NULL);
pLeader->SetSwarm(this);
return(pLeader);
}
void CSwarm::Tick()
{
size_t nLeaderCount = m_LeaderArr.GetCount();
size_t nLlamaCount = m_LlamaArr.GetCount();
m_nAge++;
// Very occasionally change a swarm type
if ((Random() & 0x7f) == 0x7f) {
size_t nIdx = m_nAge % nLeaderCount;
CLeader *pLeader = GetLeader();
pLeader->Import(m_LeaderArr[nIdx]);
delete m_LeaderArr[nIdx];
m_LeaderArr[nIdx] = pLeader;
}
// Kick a few Llamas
size_t nKickCount = nLeaderCount;
for (size_t i = 0; i < nKickCount; i++) {
m_LlamaArr[Random(int(nLlamaCount))]->Kick();
}
for (size_t i = 0; i < nLlamaCount; i++) {
m_LlamaArr[i]->Tick(this, m_LeaderArr);
}
for (size_t i = 0; i < nLeaderCount; i++) {
m_LeaderArr[i]->Tick();
}
}
///////////////////////////////////////////////////////////////////////
// Llama
void CLlama::Init(CSwarm *pSwarm)
{
p1.x = p2.x = Random(max(1, (pSwarm->GetWidth())));
p1.y = p2.y = Random(max(1, (pSwarm->GetHeight())));
dx = dy = 0;
m_idxLeader = (size_t)-1;
}
void CLlama::Kick()
{
dx += DeltaRandom(3);
dy += DeltaRandom(3);
}
void CLlama::Tick(CSwarm *pSwarm, const CLeaderArray &leaders)
{
CPoint ptClosestDelta;
int nClosestDist = INT_MAX;
size_t nLeaders = leaders.GetCount();
size_t idxClosest = 0;
p2 = p1;
for (size_t i = 0; i < nLeaders; i++) {
CPoint leader(leaders[i]->p2); // pos of leader
int nDist;
CPoint ptRel(leader.x - p2.x, leader.y - p2.y);
nDist = max(1, ABS(ptRel.x) + ABS(ptRel.y)); // approximation
if (nDist < nClosestDist) {
nClosestDist = nDist;
idxClosest = i;
ptClosestDelta = ptRel;
}
}
CLeader *pClosest = leaders[idxClosest];
// Did we switch leaders?
if (idxClosest != m_idxLeader) {
m_idxLeader = idxClosest;
m_color = pClosest->GetInitialLlamaColor();
}
// Accelerate
int acc = pClosest->GetLlamaAcc();
dx += (ptClosestDelta.x * acc) / (nClosestDist*2);
dy += (ptClosestDelta.y * acc) / (nClosestDist*2);
// Speed Limit Checks
int vel = pClosest->GetLlamaVel();
dx = max(min(dx, vel), -vel);
dy = max(min(dy, vel), -vel);
// Move and bound check
p1.x += dx;
p1.y += dy;
Bounce(p1.x, 0, pSwarm->GetWidth(), dx);
Bounce(p1.y, 0, pSwarm->GetHeight(), dy);
m_color = pClosest->GetLlamaColor(m_color);
// Draw
pSwarm->GetSurface()->Line(p1, p2, m_color);
}
///////////////////////////////////////////////////////////////////////
// Leader
CLeader::CLeader()
{
m_nMyAcc = 5;
m_nMyVel = 10;
m_nLlamaAcc = 5; // this is scaled back 1/2 when used
m_nLlamaVel = 12;
}
void CLeader::SetSwarm(CSwarm *pSwarm)
{
m_pSwarm = pSwarm;
int nBorder = m_pSwarm->GetBorder();
p1.x = p2.x = nBorder + Random(max(1, (m_pSwarm->GetWidth() - 2*nBorder)));
p1.y = p2.y = nBorder + Random(max(1, (m_pSwarm->GetHeight() - 2*nBorder)));
dx = dy = 0;
}
void CLeader::Import(const CLeader *pRHS)
{
m_pSwarm = pRHS->m_pSwarm;
p1 = pRHS->p1;
p2 = pRHS->p2;
dx = pRHS->dx;
dy = pRHS->dy;
}
void CLeader::Tick()
{
p2 = p1;
// accelerate the leader
dx += DeltaRandom(m_nMyAcc);
dy += DeltaRandom(m_nMyAcc);
// Speed Limit Checks
dx = max(min(dx, m_nMyVel), -m_nMyVel);
dy = max(min(dy, m_nMyVel), -m_nMyVel);
// Move
p1.x += dx;
p1.y += dy;
// Bounce Checks
int nBorder = m_pSwarm->GetBorder();
int nHeight = m_pSwarm->GetHeight();
int nWidth = m_pSwarm->GetWidth();
Bounce(p1.x, nBorder, nWidth-nBorder-1, dx);
Bounce(p1.y, nBorder, nHeight-nBorder-1, dy);
// Draw
m_pSwarm->GetSurface()->Line(p1, p2, RGB(255,255,255));
}
COLORREF CLeader::HSB(BYTE H, BYTE S, BYTE B)
{
unsigned char p, q, t;
int i = (int) H * 6 / 256;
float s = ((float) S) / (float) 255.0;
float f = ((float) (H * 6 - i * 256)) / (float) 255.0;
p = (BYTE) (B * (1.0 - s));
q = (BYTE) (B * (1.0 - (s * f)));
t = (BYTE) (B * (1.0 - (s * (1.0 - f))));
switch (i) {
case 0:
return RGB(B, t, p);
case 1:
return RGB(q, B, p);
case 2:
return RGB(p, B, t);
case 3:
return RGB(p, q, B);
case 4:
return RGB(t, p, B);
case 5:
return RGB(B, p, q);
}
// should never reach here
ASSERT(FALSE);
return RGB(255, 255, 255);
}
///////////////////////////////////////////////////////////////////////
// BrightLeader
CBrightLeader::CBrightLeader()
{
if (m_sColorTable[0] == 0) { // 1 time init
for (int i = 0; i <= 255; i++) {
m_sColorTable[i] = HSB((BYTE)i, 255, 255);
}
}
m_nColorCounter = Random(256);
}
void CBrightLeader::Tick()
{
if (++m_nColorCounter > 255)
m_nColorCounter = 0;
__super::Tick();
}
COLORREF CBrightLeader::GetLlamaColor(COLORREF /*oldColor*/)
{
return(m_sColorTable[m_nColorCounter]);
}
COLORREF CBrightLeader::GetInitialLlamaColor()
{
return(m_sColorTable[m_nColorCounter]);
}
///////////////////////////////////////////////////////////////////////
// HueLeader
CHueLeader::CHueLeader()
{
BYTE hue = (BYTE)Random(256);
for (int i = 0; i <= 127; i++) {
int j = min(i+32, 127);
m_ColorTable[i] = HSB(hue, 255, (BYTE)j*2);
}
for (int i = 128; i <= 255; i++) {
int j = max(i-32, 128);
m_ColorTable[i] = HSB(hue, 255, (BYTE)(511-j*2));
}
m_nColorCounter = Random(256);
}
void CHueLeader::Tick()
{
if (++m_nColorCounter > 255)
m_nColorCounter = 0;
__super::Tick();
}
COLORREF CHueLeader::GetLlamaColor(COLORREF /*oldColor*/)
{
return(m_ColorTable[m_nColorCounter]);
}
COLORREF CHueLeader::GetInitialLlamaColor()
{
return(m_ColorTable[m_nColorCounter]);
}