2016-01-27 00:52:20 chip
Page 1547
📢 PUBLIC
Item.cpp:
/*************************************************************************/
/** Item.cpp: Manage individual items. **/
/** (C)2013 nlited systems inc, Chip Doran **/
/*************************************************************************/
#include
#include
#include "Util.h"
#include "MyD2D.h"
#include "Sprite.h"
#include "Globals.h"
using namespace D2D1;
class Item { //Base class for all items.
public:
static Item *Ptr(HITEM hItem);
static int Create(HITEM *phItem, UINT TypeID, HITEM hSrc);
virtual int Destroy(void);
struct ItemLink_s *GetLink(void);
virtual int Update(HITEMS hItems, UINT Tick);
virtual int Collision(HITEMS hItems);
virtual int Explode(HITEMS hItems, HITEM hKiller);
virtual int Draw(HIMAGE hImg);
//Data
//Link is used by ItemList.cpp to manage the linked list of items.
struct ItemLink_s Link; //Must be at the top of the struct!
UINT PlayerID; //Owner PlayerID
struct Sprite_s Sprite; //Sprite information
protected:
Item(UINT ItemID);
~Item(void);
int Create2(HITEM hSrc);
void UpdateRebound(const RECT &rArena);
void UpdateWrap(const RECT &rArena);
//Data
private:
//Data
bool DoRebound; //Do items rebound or wraparound?
};
class Rocket:Item {
friend class Item; //Visibility into Item protected members.
public:
static int Create(HITEM *phItem, HITEM hSrc);
int Update(HITEMS hItems, UINT Tick);
//Data
private:
Rocket(void);
void UpdateRotation(UINT CtrlState);
//Data
bool DoRotationalMomentum; //Simple or momentum rotation?
UINT NextFire; //When rocket can fire another bullet
};
class Bullet:Item {
friend class Item;
public:
static int Create(HITEM *phItem, HITEM hSrc);
int Update(HITEMS hItems, UINT Tick);
int Collision(HITEMS hItems);
//Data
private:
Bullet(void);
int Create2(HITEM hSrc);
//Data
UINT TimeOut; //When bullet expires
};
class Rock:Item {
friend class Item;
public:
static int Create(HITEM *phItem, HITEM hSrc);
int Explode(HITEMS hItems, HITEM hSrc);
//Data
private:
Rock(void);
//Data
};
static __inline FLOAT RandF(void) { return((FLOAT)rand()/RAND_MAX); }
static __inline UINT RandI(UINT Limit) { return((UINT)(RandF()*Limit)); }
#define THRUST_ANGLE (90.0f)
static __inline FLOAT DegToRad(FLOAT Deg) { return((3.14159f*2.0f)*((Deg-THRUST_ANGLE)/360.0f)); }
UINT ExplodeShrinkage= 75;
UINT ExplodeFragment= 40;
static bool IsCollision(D2D_POINT_2F &Pt, D2D_POINT_2F &Obj, UINT Size) {
double Dist;
Dist= fmax(fabs(Obj.x-Pt.x),fabs(Obj.y-Pt.y));
if((UINT)Dist <= Size/2) {
return(1);
}
return(0);
}
/*************************************************************************/
/** Public interface **/
/*************************************************************************/
int ItemCreate(HITEM *phItem, UINT ItemID, HITEM hSrc) {
if(IsBadPtr(phItem,sizeof(*phItem),BADPTR_WRITE))
return(ERR_BADPTR);
switch(ItemID) {
case ITEM_ROCKET: return(Rocket::Create(phItem,hSrc));
case ITEM_BULLET: return(Bullet::Create(phItem,hSrc));
case ITEM_ROCK: return(Rock::Create(phItem,hSrc));
}
return(Warn(ERR_BADTYPE,__FUNCTION__": Invalid ItemID[%d]",ItemID));
}
int ItemDestroy(HITEM hItem) {
Item *pItem= Item::Ptr(hItem);
if(!pItem)
return(Warn(ERR_BADHANDLE,__FUNCTION__": Bad hItem[%X]",hItem));
return(pItem->Destroy());
}
struct ItemLink_s *ItemGetLink(HITEM hItem) {
Item *pItem= Item::Ptr(hItem);
if(!pItem)
return(0);
return(pItem->GetLink());
}
int ItemUpdate(HITEM hItem, HITEMS hList, UINT Tick) {
Item *pItem= Item::Ptr(hItem);
if(!pItem)
return(Warn(ERR_BADHANDLE,__FUNCTION__": Bad hItem[%X]",hItem));
return(pItem->Update(hList,Tick));
}
int ItemCollision(HITEM hItem, HITEMS hList) {
Item *pItem= Item::Ptr(hItem);
if(!pItem)
return(Warn(ERR_BADHANDLE,__FUNCTION__": Bad hItem[%X]",hItem));
return(pItem->Collision(hList));
}
int ItemDraw(HITEM hItem, HIMAGE hImg) {
Item *pItem= Item::Ptr(hItem);
if(!pItem)
return(Warn(ERR_BADHANDLE,__FUNCTION__": Bad hItem[%X]",hItem));
return(pItem->Draw(hImg));
}
/*************************************************************************/
/** Public internals **/
/*************************************************************************/
/** Base Item **/
/*************************************************************************/
Item *Item::Ptr(HITEM hItem) {
Item *pItem= (Item*)hItem;
if(!hItem || IsBadPtr(pItem,sizeof(*pItem),BADPTR_RW) || pItem->Link.Signature!=SIGNATURE_ITEM)
pItem= 0;
return(pItem);
}
int Item::Destroy(void) {
int Err= ERR_OK;
delete this;
return(Err);
}
struct ItemLink_s *Item::GetLink(void) {
return(&Link);
}
int Item::Update(HITEMS hItems, UINT Tick) {
int Err= ERR_OK;
RECT rArena;
ItemsGetArena(hItems,&rArena);
Sprite.PosPrev= Sprite.Pos;
Sprite.RotationPrev= Sprite.Rotation;
Sprite.FrameIDPrev= Sprite.FrameID;
Sprite.Pos.x+= Sprite.PosVel.x;
Sprite.Pos.y+= Sprite.PosVel.y;
if(DoRebound)
UpdateRebound(rArena);
else
UpdateWrap(rArena);
Sprite.Rotation+= Sprite.RotationVel;
Sprite.FrameID= RandI(2);
return(Err);
}
int Item::Collision(HITEMS hItems) {
int Err= ERR_OK;
return(Err);
}
int Item::Explode(HITEMS hItems, HITEM hKiller) {
int Err= ERR_OK;
return(Err);
}
int Item::Draw(HIMAGE hImg) {
int Err= ERR_OK;
ImgAddSprite(hImg,&Sprite);
return(Err);
}
/*************************************************************************/
/** Private internals **/
/*************************************************************************/
Item::Item(UINT ItemID) {
memset(this,0,sizeof(*this));
Link.Signature= SIGNATURE_ITEM;
Link.hItem= (HITEM)this;
Link.ItemID= ItemID;
DoRebound= 0;
Sprite.SpriteID= SPRITE_BOX;
Sprite.BitmapID= 0;
Sprite.Color= ColorF(RandF(),RandF(),RandF(),RandF());
Sprite.Pos= Sprite.PosPrev= Point2F(0,0);
Sprite.PosVel.x= RandF();
Sprite.PosVel.y= RandF();
Sprite.Rotation= Sprite.RotationPrev= 0.0f;
Sprite.RotationVel= RandF()*2.0f-1.0f;
Sprite.Size= (UINT)(RandF()*100);
Sprite.FrameID= Sprite.FrameIDPrev= 0;
}
Item::~Item(void) {
Link.Signature|= SIGNATURE_INVALID;
}
int Item::Create2(HITEM hSrc) {
int Err= ERR_OK;
Item *pSrc= Ptr(hSrc);
if(pSrc) {
PlayerID= pSrc->PlayerID;
Sprite.Pos= pSrc->Sprite.Pos;
Sprite.PosVel= pSrc->Sprite.PosVel;
Sprite.Rotation= pSrc->Sprite.Rotation;
Sprite.RotationVel= pSrc->Sprite.RotationVel;
}
return(Err);
}
void Item::UpdateRebound(const RECT &rArena) {
if(Sprite.Pos.x <= rArena.left) {
Sprite.PosVel.x= (FLOAT)fabs(Sprite.PosVel.x);
Sprite.Pos.x= rArena.left+Sprite.PosVel.x;
} else if(Sprite.Pos.x >= rArena.right) {
Sprite.PosVel.x= -(FLOAT)fabs(Sprite.PosVel.x);
Sprite.Pos.x= rArena.right+Sprite.PosVel.x;
}
if(Sprite.Pos.y <= rArena.top) {
Sprite.PosVel.y= (FLOAT)fabs(Sprite.PosVel.y);
Sprite.Pos.y= rArena.top+Sprite.PosVel.y;
} else if(Sprite.Pos.y >= rArena.bottom) {
Sprite.PosVel.y= -(FLOAT)fabs(Sprite.PosVel.y);
Sprite.Pos.y= rArena.bottom+Sprite.PosVel.y;
}
}
void Item::UpdateWrap(const RECT &rArena) {
if(Sprite.Pos.x < rArena.left)
Sprite.Pos.x= (FLOAT)(rArena.right-1);
else if(Sprite.Pos.x >= rArena.right)
Sprite.Pos.x= (FLOAT)rArena.left;
if(Sprite.Pos.y < rArena.top)
Sprite.Pos.y= (FLOAT)(rArena.bottom-1);
else if(Sprite.Pos.y >= rArena.bottom)
Sprite.Pos.y= (FLOAT)rArena.top;
}
/*************************************************************************/
/** Rocket **/
/*************************************************************************/
int Rocket::Create(HITEM *phItem, HITEM hSrc) {
int Err= ERR_OK;
Rocket *pRocket= new Rocket;
if(!pRocket) {
Err= Error(ERR_NOMEM,__FUNCTION__": Unable to alloc %d.",sizeof(*pRocket));
} else if(IsErr(Err= pRocket->Create2(hSrc))) {
delete pRocket;
} else {
*phItem= pRocket->Link.hItem;
}
return(Err);
}
int Rocket::Update(HITEMS hItems, UINT Tick) {
int Err= ERR_OK;
UINT CtrlState= 0;
struct Sprite_s *pS= &Sprite;
FLOAT ThrustDir= DegToRad(pS->Rotation);
HITEM hBullet;
ItemsGetControl(hItems,PlayerID,&CtrlState);
UpdateRotation(CtrlState);
if(CtrlState & CTRL_THRUST) {
pS->PosVel.x+= (FLOAT)cos(ThrustDir)*0.1f;
pS->PosVel.y+= (FLOAT)sin(ThrustDir)*0.1f;
}
if(CtrlState & CTRL_FIRE) {
if(Tick > NextFire) {
//Create a new Bullet item and add to the ItemList.
if(IsErr(Err= ItemCreate(&hBullet,ITEM_BULLET,(HITEM)this))) {
Err= Warn(Err,__FUNCTION__": Unable to create new bullet.");
} else if(IsErr(Err= ItemsAdd(hItems,hBullet))) {
Err= Warn(Err,__FUNCTION__": Unable to add new bullet.");
ItemDestroy(hBullet);
}
NextFire= Tick+100;
}
}
Item::Update(hItems,Tick);
pS->FrameID= (CtrlState & CTRL_THRUST) ? 1:0;
return(Err);
}
void Rocket::UpdateRotation(UINT CtrlState) {
struct Sprite_s *pS= &Sprite;
if(DoRotationalMomentum) {
if(CtrlState & CTRL_LEFT)
pS->RotationVel-= 0.2f;
else if(CtrlState & CTRL_RIGHT)
pS->RotationVel+= 0.2f;
} else {
if(CtrlState & CTRL_LEFT)
pS->RotationVel= -4.0f;
else if(CtrlState & CTRL_RIGHT)
pS->RotationVel= +4.0f;
else
pS->RotationVel= 0;
}
}
Rocket::Rocket(void):Item(ITEM_ROCKET) {
Sprite.SpriteID= SPRITE_BITMAP;
Sprite.BitmapID= BITMAP_ROCKET_PNG;
Sprite.Size= 100;
Sprite.Color.a= 1.0f;
DoRotationalMomentum= 0;
NextFire= 0;
}
/*************************************************************************/
/** Bullet **/
/*************************************************************************/
int Bullet::Create(HITEM *phItem, HITEM hSrc) {
int Err= ERR_OK;
Bullet *pBullet= new Bullet;
if(!pBullet) {
Err= Error(ERR_NOMEM,__FUNCTION__": Unable to alloc %d.",sizeof(*pBullet));
} else if(IsErr(Err= pBullet->Create2(hSrc))) {
delete pBullet;
} else {
*phItem= (HITEM)pBullet;
}
return(Err);
}
int Bullet::Update(HITEMS hItems, UINT Tick) {
int Err= ERR_OK;
if(Tick>=TimeOut) {
Err= ItemsRemove(hItems,Link.hItem);
delete this;
} else {
Err= Item::Update(hItems,Tick);
}
return(Err);
}
int Bullet::Collision(HITEMS hItems) {
int Err2,Err= ERR_OK;
HITEM hList,hNext;
Item *pItem;
bool DoDelete= 0;
if(IsErr(Err= ItemsGetNext(hItems,0,&hList))) {
Err= Error(Err,__FUNCTION__": Unable to retrieve item list.");
} else {
//Loop through all the items in ItemList
while(!IsErr(Err) && hList) {
Err2= ItemsGetNext(hItems,hList,&hNext);
if(!(pItem= Ptr(hList))) {
Err= Error(ERR_BADHANDLE,__FUNCTION__": Invalid hItem [%X]",hList);
} else if(pItem->Link.ItemID==ITEM_ROCK) {
if(IsCollision(Sprite.Pos,pItem->Sprite.Pos,pItem->Sprite.Size)) {
//If collision between a bullet and a rock,
//Explode the rock and expire the bullet.
pItem->Explode(hItems,Link.hItem);
ItemsRemove(hItems,Link.hItem);
DoDelete= 1;
break;
}
}
if(IsErr(Err2)) {
Err= Error(Err2,__FUNCTION__": Unable to retrieve next item. [%X]",hList);
} else {
hList= hNext;
}
}
}
if(DoDelete)
delete this;
return(Err);
}
Bullet::Bullet(void):Item(ITEM_BULLET) {
TimeOut= GetTickCount()+5000;
Sprite.Size= 4;
Sprite.Color= ColorF(0.25f,1.00f,1.00f,1.00f);
}
int Bullet::Create2(HITEM hSrc) {
int Err= ERR_OK;
FLOAT GunDir;
if(!IsErr(Err= Item::Create2(hSrc))) {
GunDir= DegToRad(Sprite.Rotation);
Sprite.PosVel.x+= (FLOAT)cos(GunDir)*10.0f;
Sprite.PosVel.y+= (FLOAT)sin(GunDir)*10.0f;
}
return(Err);
}
/*************************************************************************/
/** Rock **/
/*************************************************************************/
int Rock::Create(HITEM *phItem, HITEM hSrc) {
int Err= ERR_OK;
Rock *pRock= new Rock;
if(!pRock) {
Err= Error(ERR_NOMEM,__FUNCTION__": Unable to alloc %d.",sizeof(*pRock));
} else if(IsErr(Err= pRock->Create2(hSrc))) {
delete pRock;
} else {
*phItem= (HITEM)pRock;
}
return(Err);
}
int Rock::Explode(HITEMS hItems, HITEM hKiller) {
int Err= ERR_OK;
UINT ExplodeSz= Sprite.Size;
HITEM hNew;
Item *pNew;
if(Sprite.Size < 10) {
GameEvent(ghGame,EVENT_ROCK_DESTROYED);
ItemsRemove(hItems,Link.hItem);
delete this;
} else {
Sprite.Size= (Sprite.Size*ExplodeShrinkage)/100;
while(ExplodeSz>ExplodeFragment) {
if(IsErr(Err= Create(&hNew,Link.hItem)))
break;
if(pNew= Ptr(hNew)) {
pNew->Sprite.Size= Sprite.Size;
pNew->Sprite.PosVel.x+= RandF()-0.5f;
pNew->Sprite.PosVel.y+= RandF()-0.5f;
}
if(IsErr(Err= ItemsAdd(hItems,hNew)))
ItemDestroy(hNew);
ExplodeSz-= ExplodeFragment;
}
}
return(Err);
}
Rock::Rock(void):Item(ITEM_ROCK) {
}
WebV7 (C)2018 nlited | Rendered by tikope in 65.178ms | 3.147.69.25