这是一个我最初尝试开发可拖放对象,用于可能的 GUI 元素或游戏中的项目。
一款跳棋游戏,其中的棋子在释放时能自动吸附到棋盘格子的中心,这似乎是开发可拖放对象的一个良好框架。
这里使用的是 SFML 1.6 版本。
只有当移动是合法的时候,棋子才会吸附到格子中心,否则它会回到原来的位置。
动画效果包括:
1) 动画欢迎界面。(WELCOME 字样出现,几秒钟后它会展开并淡出)。
2) 一个完整的动画,将棋子摆放到棋盘上。
3) 俘获,包括将俘获的王棋分成两个棋子,然后将俘获的棋子沿着棋盘边缘移动。
4) 当一个棋子被“封王”时,会使用一个被俘获的棋子。
5) 游戏结束时的动画获胜者宣布。
游戏开始和游戏过程中的截图
本文末尾提供了一个链接,其中包含所有源代码、图像和一个可执行文件(这样你就可以立即尝试它)。
以下是源代码的部分描述。
可拖放对象。
抽象基类:dragDrop
这个类是抽象的,因为形状(圆形、矩形)在基类中是不确定的。
纯虚方法
1 2 3
|
virtual bool hit(void) = 0;// depends on shape ( rect, circle, ? )
virtual bool hitAnchor(int idx) = 0;// test if at a given anchor location
virtual void snap(void) = 0;// carries out snap-to motion in frame logic. Shape dependent.
|
一些数据成员暗示了对象的工作方式。
1 2 3
|
const static int& r_mseX;// track globally updated mouse coordinates
const static int& r_mseY;
static float snap_speed;// all common speed.
|
实际上,snap_speed 尚未投入使用!吸附运动目前“立即”发生(一个帧内完成整个距离)。 尝试启用此功能!
dragDrop 对象通过指向锚点数组的数据成员来“了解”其可能的锚点。
1 2 3
|
std::pair<int, int>* p_anchorPos;// array of allowed destination points in drag op.
int Nanchors;// # of pairs in array pointed to by p_anchorPos
int homeIdx;// index to home location among anchor array elements
|
指向的数组在 main.cpp 中静态声明,代表棋子在棋盘上的所有 32 个位置。
然后我们有这 3 个方法,它们是非虚方法(即在 dragDrop 类中定义)
1 2 3
|
bool grab(void);// call on LBUTT down - calls hit()
void drag(void);// call in frame logic
void release( int* p_IdxList, int listSz );// for use when given a sub-list of anchors from a larger array of anchors
|
传递给 release() 函数的参数提供了一个“禁止”锚点的列表。 如果 dragDrop 在其中一个上被释放,它将返回到 homeIdx 锚点。
派生类(base=dragDrop):dragDropRect
看起来我只开发了一个用于矩形 dragDrop 对象的类,即使设置抽象基类的目的就是为了允许这里的自由度! 显然,圆形 dragDrop 对象更适合于
这个应用程序。 因此,邀请读者创建和使用 dragDropCircle 对象。
在 dragDropRect 中,我们只有 int szX, szY; 以及 dragDrop 中 3 个 pv 函数的定义。
关于动画运动的一点说明
抽象基类:Leg
此类提供对用于更新位置的函数的访问。 移动的对象拥有运动的参数 t
for the motion.
1 2 3
|
float period;
virtual float x( float t ) = 0;
virtual float y( float t ) = 0;
|
同样,设置抽象基类的目的是为了允许路径形状的自由度。
在这个项目中,我只添加了一个派生类。linLeg 支持在 2 个给定点之间以恒定速度直线运动。 这是游戏中使用的唯一类型的运动。
类 (base=Leg):linLeg
1 2 3 4
|
float posix, posiy;
float velix, veliy;
virtual float x( float t ) { return( posix + velix*t ); }
virtual float y( float t ) { return( posiy + veliy*t ); }
|
游戏中只使用了一个 dragDropRect 对象 (chObj)。 这是正在移动的棋子。
类:Path
此类用于管理多个 Leg 的使用。 该类拥有对象可能在其上移动的 Legs 数组。
游戏中有四个在使用
1 2 3 4
|
Path wh_dealPath( 12, 50, 3, 400.0f, -40.0f );// 12 linLegs. One for each checker on deal.
Path bk_dealPath( 12, 50, 3, 400.0f, 620.0f );
Path aniPath( 1, 0, 0, 100.0f, 100.0f );// for general single checker motion
Path kingMePath( 1, 0, 0, 100.0f, 100.0f );// for "king me" animations
|
在 main.cpp 中,您会找到这些在程序中提供逻辑的函数。
1 2 3 4 5 6 7 8 9
|
void gameLogic(void);// called in main(). Logic branches from here.
void gameCapture_SplitAniLogic(void);// specific for capture and checker split (captured king into 2 normal checkers in the capture pool).
void gameKingMeAniLogic(void);
void gameDraw(sf::RenderWindow& rApp);// all drawing calls here
void gameHitDown(void);// event handling for the game
void gameHitUp(void);
bool menuHitDown(void);// returns false if file I/O error
void menuHitUp(void);// event handling for the buttons.
|
您还会找到按钮类,因为我倾向于自己完成所有 gui。
我希望上面的描述能为您理解代码提供足够的基础。
程序有很多可以扩展和/或改进的地方,因此有空间进行修改。
下载
我比这篇文章的最后一个版本有所改进。 下面链接的 .zip 文件包含所有源代码、所有使用的图像以及一个可执行文件,该文件现在静态链接到使用的 SFML 库。
exe 应该在没有任何外部库文件存在的情况下运行。
附件: [checkers_stat.zip]