用面向过程的思路写,对游戏设计的整体框架有了一个宏观的认知:
1.将游戏里的每一个物体/事件存在队列中,通过遍历队列来维护数据的更新。
2.通过分频来控制刷新速率(子弹/坦克/爆炸动画,频率快慢)。
写了快一天,有点累,先贴代码~有空在更新注解
#include <acllib.h>
#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
#include <algorithm>
#include <time.h>
#define SIZE 50
#define boundaryW 13
using namespace std;
ACL_Image * t_pic = new ACL_Image[4];//tank
ACL_Image * g_pic = new ACL_Image[4];//gun
ACL_Image * eg_pic = new ACL_Image[4];//enemy's gun
ACL_Image * b_pic = new ACL_Image[3];//animation bomb
ACL_Image * w_pic = new ACL_Image[3];//wall
ACL_Image * e_pic = new ACL_Image[4];//enemy
ACL_Image * lose = new ACL_Image;
enum dir
{
dir_up,
dir_down,
dir_left,
dir_right
};
typedef struct Pstruct {
int x, y;
bool operator == (const struct Pstruct & A)const {
return x == A.x&&y == A.y;
}
}posi;
typedef struct Gstruct {
posi g_posi;
dir g_dir;
int damage=50;
int group;
}gun;
typedef struct Tstruct {
posi t_posi;
int life;
dir t_dir;
int group;//0 : friend ,1 : enemy
gun t_gun;
}tank;
typedef struct Astruct {
posi p;
int fps;
int index;
}animations;
tank player;
queue<tank> enemies; //敌方坦克队列
queue<animations> ani; //动画队列
vector<dir> dire;
queue<gun> GUN;
int cnt,cnt1; //用于计时器分频
bool isMove, isFire;
int WINDOWS[boundaryW][boundaryW];
void timeEvent(int tid);
void keyEvent(int key, int event);
void draw_window();
void initPlayer();
int mm = 0;
int Setup()
{
initWindow("Test", DEFAULT, DEFAULT, 650, 650);
initPlayer();
loadImage("F:/Game Data/tankimages/0.jpg", t_pic);
loadImage("F:/Game Data/tankimages/1.jpg", t_pic + 1);
loadImage("F:/Game Data/tankimages/2.jpg", t_pic + 2);
loadImage("F:/Game Data/tankimages/3.jpg", t_pic + 3);
loadImage("F:/Game Data/tankimages/e0.jpg", e_pic);
loadImage("F:/Game Data/tankimages/e1.jpg", e_pic + 1);
loadImage("F:/Game Data/tankimages/e2.jpg", e_pic + 2);
loadImage("F:/Game Data/tankimages/e3.jpg", e_pic + 3);
loadImage("F:/Game Data/tankimages/g0.jpg", g_pic);
loadImage("F:/Game Data/tankimages/g1.jpg", g_pic + 1);
loadImage("F:/Game Data/tankimages/g2.jpg", g_pic + 2);
loadImage("F:/Game Data/tankimages/g3.jpg", g_pic + 3);
loadImage("F:/Game Data/tankimages/b0.jpg", b_pic+2);
loadImage("F:/Game Data/tankimages/b1.jpg", b_pic + 1);
loadImage("F:/Game Data/tankimages/b2.jpg", b_pic );
loadImage("F:/Game Data/tankimages/w0.jpg", w_pic+0);
loadImage("F:/Game Data/tankimages/w1.jpg", w_pic+1);
loadImage("F:/Game Data/tankimages/w2.jpg", w_pic+2);
loadImage("F:/Game Data/tankimages/eg0.jpg", eg_pic);
loadImage("F:/Game Data/tankimages/eg1.jpg", eg_pic + 1);
loadImage("F:/Game Data/tankimages/eg2.jpg", eg_pic + 2);
loadImage("F:/Game Data/tankimages/eg3.jpg", eg_pic + 3);
loadImage("F:/Game Data/tankimages/lose.jpg", lose);
registerTimerEvent(timeEvent);
registerKeyboardEvent(keyEvent);
startTimer(0, 80);
return 0;
}
void initPlayer() {
player.group = 0;
player.life = 100;
player.t_dir = dir_up;
player.t_posi.x = boundaryW / 2;
player.t_posi.y = boundaryW - 1;
while (!GUN.empty()) GUN.pop();
enemies.push(player);
tank temp;
temp.group = 1;
temp.life = 100;
temp.t_dir = dir_down;
temp.t_posi.x = 0;
temp.t_posi.y = 0;
enemies.push(temp);
for (int i = 0; i < boundaryW / 2 -1; i++) {
for (int j = 0; j < boundaryW; j++) {
if (j % 2) {
WINDOWS[j][i] = 1;
}
}
}
WINDOWS[3][boundaryW / 2] = WINDOWS[2][boundaryW / 2] = WINDOWS[boundaryW - 4][boundaryW / 2] = WINDOWS[boundaryW - 3][boundaryW / 2] = 1;
for (int i = boundaryW / 2 + 2; i < boundaryW - 1 ; i++) {
for (int j = 0; j < boundaryW; j++) {
if (j % 2) {
WINDOWS[j][i] = 1;
}
}
}
for (int i = 0; i < boundaryW; i++) {
for (int j = 0; j < boundaryW; j++) {
if (WINDOWS[i][j]) {
tank temp;
temp.group = 3;
temp.t_dir = dir_up;
temp.life = 150;
temp.t_posi.x = i;
temp.t_posi.y = j;
enemies.push(temp);
}
}
}
}
void draw_window() {
beginPaint();
clearDevice();
setPenColor(RGB(0, 0, 0));
setBrushColor(RGB(0, 0, 0));
rectangle(0, 0, 650, 650);
if (player.life > 0) {
int aniNum = ani.size();
int LenQ = GUN.size();
int NumEnemy = enemies.size();
//动画爆炸消息
while (aniNum--) {
animations tmpAni = ani.front();
ani.pop();
putImageScale(b_pic + tmpAni.fps - 1, tmpAni.p.x*SIZE, tmpAni.p.y*SIZE, SIZE, SIZE);
if (cnt1 > 2)cnt1 = 0;
else if (cnt1 == 2) {
cnt1 = 0;
tmpAni.fps--;
}
if (tmpAni.fps) { ani.push(tmpAni); }
}
//坦克移动消息
if (dire.empty()) isMove = false;
else isMove = true;
NumEnemy = enemies.size();
while (NumEnemy--)
{
tank tmpEnemy;
tmpEnemy = enemies.front();
enemies.pop();
//敌方
if (tmpEnemy.group == 3) {
enemies.push(tmpEnemy);
continue;
}
else if (tmpEnemy.group == 1) {
if (cnt >= 4) {
bool flag = true;
if (player.t_posi.x == tmpEnemy.t_posi.x) {
flag = false;
gun * bullet = new gun;
bullet->g_posi = tmpEnemy.t_posi;
bullet->group = 1;
if (player.t_posi.y > tmpEnemy.t_posi.y) bullet->g_dir = dir_down;
else bullet->g_dir = dir_up;
GUN.push(*bullet);
}
else if (player.t_posi.y == tmpEnemy.t_posi.y) {
flag = false;
gun * bullet = new gun;
bullet->g_posi = tmpEnemy.t_posi;
bullet->group = 1;
if (player.t_posi.x > tmpEnemy.t_posi.x) bullet->g_dir = dir_right;
else bullet->g_dir = dir_left;
GUN.push(*bullet);
}
if (flag) {
if (tmpEnemy.t_posi.y == boundaryW - 1)mm++;
if (tmpEnemy.t_posi.y == 0)mm++;
if (mm % 2 == 0) {
tmpEnemy.t_dir = dir_up;
tmpEnemy.t_posi.y--;
}
else {
tmpEnemy.t_dir = dir_down;
tmpEnemy.t_posi.y++;
}
}
}
}
else {
//我方
if (cnt >= 4) {
player = tmpEnemy;
//开火消息
if (isFire) {
isFire = false;
gun * bullet = new gun;
bullet->g_posi = tmpEnemy.t_posi;
bullet->group = 0;
bullet->g_dir = tmpEnemy.t_dir;
GUN.push(*bullet);
}
if (isMove) {
bool isTurn = false;
if (tmpEnemy.t_dir != dire.back()) {
isTurn = true;
tmpEnemy.t_dir = dire.back();
}
switch (tmpEnemy.t_dir) {
case 0:
if (!isTurn && tmpEnemy.t_posi.y - 1 >= 0 && !WINDOWS[tmpEnemy.t_posi.x][tmpEnemy.t_posi.y - 1]) tmpEnemy.t_posi.y--;
break;
case 1:
if (!isTurn && tmpEnemy.t_posi.y + 1 < boundaryW && !WINDOWS[tmpEnemy.t_posi.x][tmpEnemy.t_posi.y + 1]) tmpEnemy.t_posi.y++;
break;
case 2:
if (!isTurn && tmpEnemy.t_posi.x - 1 >= 0 && !WINDOWS[tmpEnemy.t_posi.x - 1][tmpEnemy.t_posi.y]) tmpEnemy.t_posi.x--;
break;
case 3:
if (!isTurn && tmpEnemy.t_posi.x + 1 < boundaryW && !WINDOWS[tmpEnemy.t_posi.x + 1][tmpEnemy.t_posi.y]) tmpEnemy.t_posi.x++;
break;
}
}
}
}
if (tmpEnemy.group == 0) putImageScale(t_pic + tmpEnemy.t_dir, tmpEnemy.t_posi.x*SIZE, tmpEnemy.t_posi.y*SIZE, SIZE, SIZE);
else putImageScale(e_pic + tmpEnemy.t_dir, tmpEnemy.t_posi.x*SIZE, tmpEnemy.t_posi.y*SIZE, SIZE, SIZE);
enemies.push(tmpEnemy);
}
if (cnt >= 4)cnt = 0;
NumEnemy = enemies.size();
//墙壁消息
while (NumEnemy--)
{
tank tempEnemy;
tempEnemy = enemies.front();
enemies.pop();
if (tempEnemy.group == 3) {
int p = tempEnemy.life / 50;
switch (p) {
case 1:
tempEnemy.t_dir = dir_left;
break;
case 2:
tempEnemy.t_dir = dir_down;
break;
case 3:
tempEnemy.t_dir = dir_up;
break;
}
putImageScale(w_pic + tempEnemy.t_dir, tempEnemy.t_posi.x*SIZE, tempEnemy.t_posi.y*SIZE, SIZE, SIZE);
}
enemies.push(tempEnemy);
}
NumEnemy = enemies.size();
//子弹信息
while (LenQ > 0)
{
LenQ--;
bool isHit = false;;
gun temp = GUN.front();
GUN.pop();
dir direct = temp.g_dir;
switch (direct)
{
case dir_up:
temp.g_posi.y--;
break;
case dir_down:
temp.g_posi.y++;
break;
case dir_left:
temp.g_posi.x--;
break;
case dir_right:
temp.g_posi.x++;
break;
}
if (temp.g_posi.x < 0 || temp.g_posi.x >= boundaryW || temp.g_posi.y < 0 || temp.g_posi.y >= boundaryW) {
continue;
}
NumEnemy = enemies.size();
while (NumEnemy > 0) {
NumEnemy--;
tank tempEnemy = enemies.front();
enemies.pop();
if (temp.g_posi == tempEnemy.t_posi) {
isHit = true;
if (temp.group != tempEnemy.group) tempEnemy.life -= temp.damage;
if (tempEnemy.life <= 0) {
if (tempEnemy.group == 3) {
WINDOWS[tempEnemy.t_posi.x][tempEnemy.t_posi.y] = 0;
}
else if (tempEnemy.group == 0) {
player = tempEnemy;
}
tempEnemy.life = 0;
animations tt;
tt.p = temp.g_posi;
tt.fps = 3;
tt.index = 0;//bomb animation
ani.push(tt);
}
}
if (tempEnemy.life) {
enemies.push(tempEnemy);
}
if (isHit)break;
}
if (!isHit) {
GUN.push(temp);
if (temp.group == 0) putImageScale(g_pic + direct, temp.g_posi.x*SIZE, temp.g_posi.y*SIZE, SIZE, SIZE);
else putImageScale(eg_pic + direct, temp.g_posi.x*SIZE, temp.g_posi.y*SIZE, SIZE, SIZE);
}
}
}
else
{
putImageScale(lose, 0, 0, 650, 650);
}
endPaint();
}
void timeEvent(int tid) {
cnt++;
cnt1++;
draw_window();
}
void keyEvent(int key, int event) {
if (key == VK_UP) {
if (event == KEY_DOWN) {
if(find(dire.begin(),dire.end(),dir_up)==dire.end()) dire.push_back(dir_up);
}
else if (event == KEY_UP) {
if (!dire.empty()) dire.erase(find(dire.begin(), dire.end(), dir_up));
}
}
if (key == VK_DOWN) {
if (event == KEY_DOWN) {
if (find(dire.begin(), dire.end(), dir_down) == dire.end()) dire.push_back(dir_down);
}
else if (event == KEY_UP) {
if (!dire.empty()) dire.erase(find(dire.begin(), dire.end(), dir_down));
}
}
if (key == VK_LEFT) {
if (event == KEY_DOWN) {
if (find(dire.begin(), dire.end(), dir_left) == dire.end()) dire.push_back(dir_left);
}
else if (event == KEY_UP) {
if (!dire.empty()) dire.erase(find(dire.begin(), dire.end(), dir_left));
}
}
if (key == VK_RIGHT) {
if (event == KEY_DOWN) {
if (find(dire.begin(), dire.end(), dir_right) == dire.end()) dire.push_back(dir_right);
}
else if (event == KEY_UP) {
if(!dire.empty()) dire.erase(find(dire.begin(), dire.end(), dir_right));
}
}
if (key == VK_SPACE) {
if (event == KEY_UP) {
isFire = true;
}
}
}