using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectDraw;
using Global;
using Global.GlobalClass;
using KillerInstinct.DirectX;
namespace KillerInstinct.Sprites{
public abstract class SpriteClass
{
private const int MAX_ENERGY = 200; // maximum allowed energy
public const int MAX_LAYER = 10;
public const int LAYER_BACKGROUND = 0;
public const int LAYER_POWERUP = 1;
public const int LAYER_TANK = 2;
//public const int LAYER_4 = 3;
//public const int LAYER_5 = 4;
//public const int LAYER_6 = 5;
public const int LAYER_SHOT = 6;
public const int LAYER_TREE = 7;
public const int LAYER_EXPLOSION = 8;
public const int LAYER_TOP = 9;
//
public string file
{
get
{ return (global.spriteList.resourceList[idx].file); }
set
{ global.spriteList.resourceList[idx].file = value; }
}
public Surface surface
{
get
{ return (global.spriteList.resourceList[idx].surface); }
set
{ global.spriteList.resourceList[idx].surface = value; }
}
public SurfaceDescription description
{
get
{ return (global.spriteList.resourceList[idx].description); }
set
{ global.spriteList.resourceList[idx].description = value; }
}
public Bitmap bmp
{
get
{ return (global.spriteList.resourceList[idx].bmp); }
set
{ global.spriteList.resourceList[idx].bmp = value; }
}
//...
public int idx = -1; // resourceList[] position of our-self
public ulong parentId = ulong.MaxValue; // global id of parent
public ulong globalId = 0; // this sprite's unique identifier
public int playerId = 0; // if a player, player's unique id
public string playerName = "";
public byte colorKey;
private int m_createTime = 0;
private int m_deleteTime = 0;
public Rectangle frame;
public int whichFrame = 0;
public int framesCount = 1;
public int framesPerRow = 1;
public int framesPerColumn = 1;
public int frameAngle = 9;
public Rectangle CollisionBox;
public float shrink_factor = 1f;
// object attributes
public float speed = 0;
public float maxSpeed = 0;
public float maxSpeedBack = 0;
public float acceleration = 0;
public float posX = 0;
public float posY = 0;
public float direction = 0;
private bool initialized = false;
public int layer = 0;
// to avoid early collision detection when tank shoots alternativ
public bool active = true;
public CollisionType collisionType = CollisionType.NoCollision;
public int collisionKey = CONST.COLLISION_KEY_WHITE;
public int Skill = 0;
private int m_energy = 0;
public int m_score = 0;
public int Energy
{
get
{ return m_energy; }
set
{
// remember energy
int oldEnergy = m_energy;
// set energy
m_energy = value;
// if we over-stepped max allowed energy, top off at maximum
if (m_energy > MAX_ENERGY)
m_energy = MAX_ENERGY;
// if we dropped below '0', set tank to inactive and top off at '0'
else if (m_energy < 0)
{
active = false;
m_energy = 0;
}
// adjust total enemy energy with new value (if not ourself)
if (global.PC.MyPlayerName != playerName)
global.spriteList.EnemyEnergy += (m_energy-oldEnergy);
}
}
public int CreateTime
{
get
{ return m_createTime; }
}
public int DeleteTime
{
get
{ return m_deleteTime; }
}
public enum CollisionType
{
NoCollision,
BoundingBox,
Pixel
}
public SpriteClass()
{
}
public void ChangeBitmap(string file)
{
Init(file, CONST.COLORKEY_NO, posX, posY);
}
public void ChangeBitmap(string file, int frameCount)
{
this.framesCount = frameCount;
Init(file, CONST.COLORKEY_NO, posX, posY);
}
public void ChangeBitmap(string file, byte colorKey)
{
Init(file, colorKey, posX, posY);
}
public void ChangeBitmap(string file, int frameCount, byte colorKey)
{
this.framesCount = frameCount;
Init(file, colorKey, posX, posY);
}
// OVERLOADED: calls Init() with delete time of '0'
public void Init(String strFile, byte bColorKey, float x, float y)
{
Init(strFile, bColorKey, x, y, 0);
}
public void Init(String strFile, byte bColorKey, float x, float y, int deleteTime)
{
global.dbg.Out(Debug.DBG2, "SpriteClass.Init called, file=[" + strFile + "] xy=[" + x + "/" + y + "] delTime=[" + deleteTime + "]");
// in debug mode, set a default name for this object (will get over-written by child classes)
if (global.dbg.Level == Debug.DBG3)
playerName = this.ToString() + global.random(1, 100);
try
{
idx = global.spriteList.GetResourceIdx(strFile);
if (idx > -1)
{
globalId = global.spriteList.spriteCount;
colorKey = bColorKey;
posX = x;
posY = y;
framesPerColumn = framesCount / framesPerRow;
ColorKey colorKeythis = new ColorKey();
switch (colorKey)
{
case CONST.COLORKEY_NO:
break;
case CONST.COLORKEY_BLACK:
colorKeythis = new ColorKey();
colorKeythis.ColorSpaceLowValue = Color.Black.ToArgb();
colorKeythis.ColorSpaceHighValue = Color.Black.ToArgb();
surface.SetColorKey(ColorKeyFlags.SourceDraw, colorKeythis);
bmp.MakeTransparent(Color.Black);
break;
case CONST.COLORKEY_WHITE:
colorKeythis = new ColorKey();
colorKeythis.ColorSpaceLowValue = Color.White.ToArgb();
colorKeythis.ColorSpaceHighValue = Color.White.ToArgb();
surface.SetColorKey(ColorKeyFlags.SourceDraw, colorKeythis);
bmp.MakeTransparent(Color.White);
break;
}
// save creation time
m_createTime = System.Environment.TickCount;
// set time to delete sprite, 0 = never delete
m_deleteTime = deleteTime;
initialized = true;
}
else
{
global.dbg.Out(Debug.ERR, "SpriteClass.Init: Cannot find resource index [" + strFile + "]. Exiting...");
MessageBox.Show("Cannot find resource index [" + strFile + "]. Exiting...");
global.options.initialized = false;
}
}
catch (Exception e)
{
global.dbg.Out(Debug.WARN, "SpriteClass.Init exception: x=[" + posX + "] y=[" + posY + "] whichFrame=[" + whichFrame + "] getFRect=[" + GetBitmapFrameRect(whichFrame) + "] file=[" + file + "]");
global.dbg.Out(Debug.WARN, "SpriteClass.Init exception: " + e);
}
if (shrink_factor != 1)
{
// 150/2 = 75 - 30 = 35
Point middle = GetFrameMiddle();
CollisionBox.Width = (int)(frame.Width * shrink_factor);
CollisionBox.Height = (int)(frame.Height * shrink_factor);
CollisionBox.X = frame.Width/2 - CollisionBox.Width;
CollisionBox.Y = frame.Height/2 - CollisionBox.Height;
}
else
{
CollisionBox.X = 0;
CollisionBox.Y = 0;
CollisionBox.Width = frame.Width;
CollisionBox.Height = frame.Height;
}
//global.dbg.Out(Debug.TRACE, "collisionBox=" + CollisionBox);
}
// returns a random resource file based on searchText
public static string GetRandomResource(string searchText)
{
global.dbg.Out(Debug.DBG2, "GetRandomResource searching for [" + searchText + "].");
string resourceName = "";
try
{
// get array of Tank*.bmp files
string[] files = Directory.GetFiles(CONST.DIR_BITMAP, searchText);
if (files.Length > 0)
{
global.dbg.Out(Debug.DBG2, "Found [" + files.Length + "] resource files.");
// return random resource file name, e.g. ".\Bitmaps\Win1.bmp"
resourceName = files[global.random(0, files.Length-1)];
global.dbg.Out(Debug.DBG2, "Using random resource file from resource: [" + resourceName + "]");
}
else
{
global.dbg.Out(Debug.ERR, "No resources were found to load.");
}
}
catch (Exception e)
{
global.dbg.Out(Debug.ERR, "An error occurred trying to read list of resources: " + e);
MessageBox.Show("An error occurred trying to read list of resources: " + e, "Unable to find resources");
}
return (resourceName);
}
public void Restore()
{
if (initialized)
{
surface.Dispose();
surface = null;
description = new SurfaceDescription();
surface = new Surface(file, description, global.DC.Draw);
ColorKey colorKeythis = new ColorKey();
switch (colorKey)
{
case CONST.COLORKEY_NO:
break;
case CONST.COLORKEY_BLACK:
colorKeythis = new ColorKey();
colorKeythis.ColorSpaceLowValue = 0;
colorKeythis.ColorSpaceHighValue = 0;
surface.SetColorKey(ColorKeyFlags.SourceDraw, colorKeythis);
break;
case CONST.COLORKEY_WHITE:
colorKeythis = new ColorKey();
colorKeythis.ColorSpaceLowValue = 65535;
colorKeythis.ColorSpaceHighValue = 65535;
surface.SetColorKey(ColorKeyFlags.SourceDraw, colorKeythis);
break;
}
}
}
public Rectangle GetBitmapFrameRect(int FrameNumber)
{
////////////
//if( this.file.StartsWith(".\\Resources\\Bitmaps\\TankTeam") )
//global.dbg.Out(Debug.TRACE, "GetBitmapFrameRect (before): [" + this.file + "] frame.X=[" + frame.X + "] frame.Y=[" + frame.Y + "] frame.Width=[" + frame.Width + "] frame.Height=[" + frame.Height + "]");
for (int i=1; i<=framesPerColumn; i++)
{
if (FrameNumber < (framesPerRow * i))
{
int frameColumn = FrameNumber % framesPerRow;
frame.X = frame.Width * frameColumn;
frame.Y = frame.Height * (i-1);
//global.dbg.Out(Debug.DBG2, "SpriteClass.GetBitmapFrameRect frameCol=[" + frameColumn + "] frame.X=[" + frame.X + "] frame.Y=[" + frame.Y + "] [" + this.file + "]");
break;
}
}
/*if (posX + frame.Width > global.options.SCR_WIDTH)
{
frame.Width -= ((int)posX + frame.Width - global.options.SCR_WIDTH);
}
if (posY + frame.Height > global.options.SCR_HEIGHT)
{
frame.Height -= ((int)posY + frame.Height - global.options.SCR_HEIGHT);
}*/
////////////
if( this.file.StartsWith(".\\Resources\\Bitmaps\\TankTeam") )
{
//global.dbg.Out(Debug.TRACE, "GetBitmapFrameRect (after): [" + this.file + "] frame.X=[" + frame.X + "] frame.Y=[" + frame.Y + "] frame.Width=[" + frame.Width + "] frame.Height=[" + frame.Height + "]");
//global.dbg.Out(Debug.TRACE, "GetBitmapFrameRect-----------------------------------------------------------------------------");
}
return frame;
}
/*public Rectangle GetCollisionRect(int FrameNumber)
{
for (int i=1; i<=framesPerColumn; i++)
{
if (FrameNumber < (framesPerRow * i))
{
int frameColumn = FrameNumber % framesPerRow;
CollisionBox.X = (frame.Width * frameColumn) + (int)(frame.Width-frame.Width*shrink_factor);
CollisionBox.Y = (frame.Height * (i-1)) + (int)(frame.Height-frame.Height*shrink_factor);
//global.dbg.Out(Debug.DBG2, "SpriteClass.GetBitmapFrameRect frameCol=[" + frameColumn + "] frame.X=[" + frame.X + "] frame.Y=[" + frame.Y + "] [" + this.file + "]");
break;
}
}
return CollisionBox;
}*/
public Point GetFrameMiddle()
{
return (new Point((int)(posX+frame.Width/2), (int)(posY+frame.Height/2)));
}
public void Draw()
{
/*global.dbg.Out(Debug.TRACE, "---------------------------------");
global.dbg.Out(Debug.TRACE, "file = " + file);
global.dbg.Out(Debug.TRACE, "posX = " + posX);
global.dbg.Out(Debug.TRACE, "posY = " + posY);
global.dbg.Out(Debug.TRACE, "speed = " + speed);
global.dbg.Out(Debug.TRACE, "whichFrame = " + whichFrame);
global.dbg.Out(Debug.TRACE, "frame.X = " + frame.X);
global.dbg.Out(Debug.TRACE, "frame.Y = " + frame.Y);*/
try
{
if (initialized)
{
// does any specific variable updating within each sprite
if (active) Update();
// draw new values (which were just Update()'d)
global.dbg.Out(Debug.DBG3, "SpriteClass.Draw called");
// make sure the sprite is on-screen
if (global.DC.CheckOnScreen(new Rectangle((int)posX+1, (int)posY+1, frame.Width-1, frame.Height-1)))
{
if (colorKey == CONST.COLORKEY_NO)
global.DC.Back.DrawFast((int)posX, (int)posY, surface, GetBitmapFrameRect(whichFrame), DrawFastFlags.Wait);
else
global.DC.Back.DrawFast((int)posX, (int)posY, surface, GetBitmapFrameRect(whichFrame), DrawFastFlags.Wait | DrawFastFlags.SourceColorKey);
}
//DEBUG: draw collision boxes
//if (this.GetType() == typeof(TreeClass))
// global.DC.DrawBox((int)posX+CollisionBox.X, (int)posY+CollisionBox.Y,CollisionBox.Width,CollisionBox.Height, Color.HotPink);
}
}
catch (Exception e)
{
//TODO: this exception occurs every once in a while ... ???
global.dbg.Out(Debug.WARN, "SpriteClass.Draw exception: id=[" + globalId + "] x=[" + posX + "] y=[" + posY + "] whichFrame=[" + whichFrame + "] getFRect=[" + GetBitmapFrameRect(whichFrame) + "] colorKey=[" + colorKey + "] file=[" + file + "]");
global.dbg.Out(Debug.WARN, "SpriteClass.Draw exception: " + e);
}
}
public void TurnLeft()
{
if (active)
{
if (whichFrame == framesCount-1)
whichFrame = 0;
else
whichFrame++;
}
}
public void TurnRight()
{
if (active)
{
if (whichFrame == 0)
whichFrame = framesCount-1;
else
whichFrame--;
}
}
public float Speed
{
get
{
return speed;
}
set
{
if (active)
{
if ((value>=maxSpeedBack) && (value<=maxSpeed))
speed = value;
}
}
}
public void SpeedUp()
{
if (active)
{
//if (global.DC.CheckOnScreen(new Rectangle((int)posX+1, (int)posY+1, frame.Width-1, frame.Height-1)))
if (speed < maxSpeed)
speed += acceleration;
}
}
public void SpeedDown()
{
if (active)
{
if (speed >= -maxSpeedBack)
speed -= acceleration;
}
}
public abstract void Update();
public bool Collision(SpriteClass s)
{
// see if sprites can collide with each other
if (collisionType!=CollisionType.NoCollision && s.collisionType!=CollisionType.NoCollision)
{
global.dbg.Out(Debug.DBG3, "Checking Collision: BoundingBox...");
//global.dbg.Out(Debug.TRACE, "COLLISION id=[" + globalId + "] parentId=[" + parentId + "] s.id=[" + s.globalId + "] s.pId=[" + s.parentId + "]");
try
{
// bounding box collision detection
Rectangle rIntersect = new Rectangle((int)posX+CollisionBox.X, (int)posY+CollisionBox.Y, CollisionBox.Width, CollisionBox.Height);
Rectangle r2 = new Rectangle((int)s.posX+s.CollisionBox.X, (int)s.posY+s.CollisionBox.Y, s.CollisionBox.Width, s.CollisionBox.Height);
Bitmap bmp2 = null;
// get intersecting rectangle
rIntersect.Intersect(r2);
if (rIntersect.Width!=0 && rIntersect.Height!=0)
{
// if both sprites have BoundingBox collision types...
if ((collisionType == CollisionType.BoundingBox) && (s.collisionType == CollisionType.BoundingBox))
{
global.dbg.Out(Debug.DBG2, "\tBOUNDING BOX COLLISION OCCURRED: id=[" + globalId + "] parentId=[" + parentId + "] s.id=[" + s.globalId + "] s.pId=[" + s.parentId + "]");
return true;
}
// if one sprite is BoundingBox collision and the other is Pixel collision...
else if ((collisionType == CollisionType.BoundingBox) && (s.collisionType == CollisionType.Pixel) ||
(collisionType == CollisionType.Pixel) && (s.collisionType == CollisionType.BoundingBox))
{
global.dbg.Out(Debug.DBG3, "Checking Collision: boundingbox-pixel...");
Rectangle overlapped;
BitmapData bmpData;
// if first sprite has Pixel collision type...
if (collisionType == CollisionType.Pixel)
{
// get 'overlapped' absolute position in .bmp file
overlapped = GetBitmapFrameRect(whichFrame);
overlapped.X += rIntersect.X - (int)posX;
overlapped.Y += rIntersect.Y - (int)posY;
overlapped.Height = rIntersect.Height;
overlapped.Width = rIntersect.Width;
//global.dbg.Out(Debug.TRACE, " firstPixel overlapped=" + overlapped);
//global.dbg.Out(Debug.TRACE, " rIntersect=" + rIntersect);
//global.dbg.Out(Debug.TRACE, " r2=" + r2);
// lock bits in .bmp file
bmpData = bmp.LockBits(overlapped, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);
}
// if second sprite has Pixel collision type...
else
{
// get 'overlapped' absolute position in .bmp file
overlapped = s.GetBitmapFrameRect(s.whichFrame);
overlapped.X += rIntersect.X - (int)s.posX;
overlapped.Y += rIntersect.Y - (int)s.posY;
overlapped.Height = rIntersect.Height;
overlapped.Width = rIntersect.Width;
//global.dbg.Out(Debug.TRACE, " secondPixel overlapped=" + overlapped);
// lock bits in .bmp file
bmpData = s.bmp.LockBits(overlapped, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);
}
// check where sprites collide
int scanWidth = bmpData.Stride;
System.IntPtr Scan = bmpData.Scan0;
unsafe
{
byte* p1 = (byte*)Scan;
// get # of lines to scan using "scan line width" - color of pixel stored in one WORD
int nLines = scanWidth - rIntersect.Width*2;
for(int y=0; y<rIntersect.Height; ++y)
{
for(int x=0; x<rIntersect.Width; ++x)
{
// if any NON-transparent(0) pixel hits another NON-transparent pixel
if (p1[0] != 0 && p1[1] != 0)
{
global.dbg.Out(Debug.DBG2, "\tBOUND-PIXEL COLLISION OCCURRED: id=[" + globalId + "] parentId=[" + parentId + "] s.id=[" + s.globalId + "] s.pId=[" + s.parentId + "]");
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: this.posXY=" + this.posX + "," + this.posY);
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: this.frame=" + this.frame);
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: s.posXY=" + s.posX + "," + s.posY);
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: s.frame=" + s.frame);
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: rInt.frame=" + rIntersect);
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: scanWidth=" + scanWidth + " nLines=" + nLines);
//global.dbg.Out(Debug.DBG1, "\tBOUND-PIXEL COLLISION: p1[0]=" + p1[0] + " p1[1]=" + p1[1]);
//global.dbg.Out(Debug.DBG1, ""
// if first sprite has Pixel collision type...
if (collisionType == CollisionType.Pixel)
bmp.UnlockBits(bmpData);
// if second sprite has Pixel collision type...
else
s.bmp.UnlockBits(bmpData);
return true;
}
p1 += 2;
}
// jump to next line
p1 += nLines;
}
}
// if first sprite has Pixel collision type...
if (collisionType == CollisionType.Pixel)
bmp.UnlockBits(bmpData);
// if second sprite has Pixel collision type...
else
s.bmp.UnlockBits(bmpData);
return false;
}
// if both sprites have Pixel collision types...
else
{
global.dbg.Out(Debug.DBG3, "Checking Collision: pixel-pixel...");
// pixel collision detection
Rectangle overlapped1 = GetBitmapFrameRect(whichFrame);
overlapped1.X += rIntersect.X - (int)posX;
overlapped1.Y += rIntersect.Y - (int)posY;
overlapped1.Height = rIntersect.Height;
overlapped1.Width = rIntersect.Width;
Rectangle overlapped2 = s.GetBitmapFrameRect(s.whichFrame);
overlapped2.X += rIntersect.X - (int)s.posX;
overlapped2.Y += rIntersect.Y - (int)s.posY;
overlapped2.Height = rIntersect.Height;
overlapped2.Width = rIntersect.Width;
BitmapData bmpData1;
BitmapData bmpData2;
// if other sprite 's' is the same bitmap, only lock area ONE TIME!
if (idx == s.idx)
{
bmpData1 = bmp.LockBits(overlapped1, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);
bmp2 = (Bitmap)bmp.Clone();
bmpData2 = bmp2.LockBits(overlapped2, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);
}
// otherwise lock both areas (for each bitmap)
else
{
bmpData1 = bmp.LockBits(overlapped1, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);
bmpData2 = s.bmp.LockBits(overlapped2, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);
}
int scanWidth = bmpData1.Stride;
System.IntPtr Scan1 = bmpData1.Scan0;
System.IntPtr Scan2 = bmpData2.Scan0;
unsafe
{
byte* p1 = (byte*)Scan1;
byte* p2 = (byte*)Scan2;
// get # of lines to scan using "scan line width" - color of pixel stored in one WORD
int nLines = scanWidth - rIntersect.Width*2;
for(int y=0; y<rIntersect.Height; ++y)
{
for(int x=0; x<rIntersect.Width; ++x)
{
// if any NON-transparent(0) pixel hits another NON-transparent pixel
if (p1[0] != 0 && p1[1] != 0 && p2[0] != 0 && p2[1] != 0)
{
global.dbg.Out(Debug.DBG2, "\tPIXEL COLLISION OCCURRED: id=[" + globalId + "] parentId=[" + parentId + "] s.id=[" + s.globalId + "] s.pId=[" + s.parentId + "]");
//global.dbg.Out(Debug.DBG1, "\tPIXEL COLLISION: this.frame=" + this.frame);
//global.dbg.Out(Debug.DBG1, "\tPIXEL COLLISION: s.frame=" + s.frame);
//global.dbg.Out(Debug.DBG1, "\tPIXEL COLLISION: rInt.frame=" + rIntersect);
//global.dbg.Out(Debug.DBG1, "\tPIXEL COLLISION: scanWidth=" + scanWidth + " nLines=" + nLines);
//global.dbg.Out(Debug.DBG1, "\tPIXEL COLLISION: p1[0]=" + p1[0] + " p1[1]=" + p1[1] + " -- p2[0]=" + p2[0] + " p2[1]=" + p2[1]);
bmp.UnlockBits(bmpData1);
// if other sprite 's' is the NOT the same bitmap, unlock second area
if (idx != s.idx)
s.bmp.UnlockBits(bmpData2);
return true;
}
p1 += 2;
p2 += 2;
}
// jump to next line
p1 += nLines;
p2 += nLines;
}
}
bmp.UnlockBits(bmpData1);
// if other sprite 's' is the NOT the same bitmap, unlock second area
if (idx != s.idx)
s.bmp.UnlockBits(bmpData2);
else
bmp2.UnlockBits(bmpData2);
return false;
}
}
}
catch (Exception e)
{
throw new Exception("Collision detection: " + e);
}
}
return false;
}
public abstract void ReactToCollision(SpriteClass s);
//
}
}
|