616 lines
9.7 KiB
C++
616 lines
9.7 KiB
C++
/*
|
||
|
||
1.导入素材
|
||
2.实现游戏场景界面初始化
|
||
3.实现游戏界面顶部工具栏
|
||
4.实现工具栏中的植物卡牌
|
||
|
||
*/
|
||
#include <graphics.h> // 引用图形库头文件
|
||
#include<stdlib.h>
|
||
#include<stdio.h>
|
||
#include"tools.h"
|
||
#include<time.h>
|
||
#define Wiw_width 900
|
||
#define Wiw_heigh 600
|
||
|
||
|
||
enum { WANDOU, XRK, JIANGUO,ZHIWU_COUNT };//枚举定义植物类型和数量
|
||
//将卡牌数量放到枚举最后一个,即可巧妙的自动表示数组长度(即卡牌数量)
|
||
|
||
IMAGE imgBg;//表示背景图片
|
||
IMAGE imgToor;//表示工具栏
|
||
IMAGE imgCards[ZHIWU_COUNT];//植物卡牌数组
|
||
IMAGE *imgplt[ZHIWU_COUNT][20];//每个植物有多个图片,形成动态效果
|
||
|
||
|
||
int percentX, percentY;//定义全局变量,当前选中植物所在坐标
|
||
int percent_plant;//0:没有选中 1:选中第一种
|
||
struct plant
|
||
{
|
||
int type;//第几种植物,0没有植物,1第一种植物
|
||
int frameIndex;//序列帧序号
|
||
|
||
};
|
||
struct plant map[5][8];//地图上可以放五行八列的植物
|
||
|
||
struct sunshineBall
|
||
{
|
||
//阳光位置
|
||
int x, y;//飘落过程中的坐标位置,x不变
|
||
int frameIndex;//阳光图片帧序号
|
||
int fixedY;//最终位置
|
||
bool used;//是否在使用
|
||
int timer;//计时器为了使阳光存在时间加长
|
||
};
|
||
//池
|
||
/*
|
||
|
||
预先准备10个阳光球
|
||
如果频繁的创建阳光球不方便管理
|
||
|
||
*/
|
||
struct sunshineBall balls[10];
|
||
|
||
//定义一个图片数组储存阳光
|
||
IMAGE imgSun[29];
|
||
|
||
int Suncount;//阳光的数量
|
||
|
||
|
||
bool fileExist(const char* Zwname)
|
||
{
|
||
FILE* fp = fopen(Zwname, "r");
|
||
if (fp == NULL)
|
||
{
|
||
return false;
|
||
|
||
}
|
||
else
|
||
{
|
||
fclose(fp);
|
||
return true;
|
||
|
||
}
|
||
|
||
|
||
}
|
||
void gameInit()
|
||
{
|
||
int j;
|
||
//加载背景图片
|
||
//把字符集修改为多字符集
|
||
loadimage(&imgBg, "res\\map0.jpg");
|
||
//加载工具栏图片
|
||
loadimage(&imgToor, "res\\bar5.png");
|
||
|
||
memset(imgplt, 0, sizeof(imgplt));
|
||
|
||
memset(map, 0, sizeof(map));
|
||
memset(balls, 0, sizeof(balls));
|
||
//加载多个植物卡牌图片
|
||
int i;
|
||
int suni;
|
||
//生成植物卡牌文件名
|
||
char Zwname[1024];
|
||
char Sunname[1024];
|
||
for (i = 0; i < ZHIWU_COUNT; i++)
|
||
{
|
||
//???
|
||
sprintf_s(Zwname, sizeof(Zwname), "res\\Cards\\card_%d.png", i + 1);
|
||
loadimage(&imgCards[i], Zwname);
|
||
|
||
for (j = 0; j < 20; j++)
|
||
{
|
||
sprintf_s(Zwname, sizeof(Zwname), "res\\Plants\\%d\\%d.png", i,j + 1);
|
||
//先判断文件是否存在
|
||
//通过文件是否能打开判断是否存在
|
||
if (fileExist(Zwname))
|
||
{
|
||
//开始设置的*imgplt是空指针,直接加载会崩掉
|
||
//所以要分配内存
|
||
imgplt[i][j] = new IMAGE;//因为这个图形库函数是c++,分配内存不能用malloc,用c++的方式来分配内存
|
||
//上方代码是c++内容,暂时看不懂
|
||
loadimage(imgplt[i][j], Zwname);
|
||
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
percent_plant = 0;
|
||
|
||
//阳光池
|
||
//memset(balls, 0, sizeof(balls));
|
||
for (suni = 0; suni < 29; suni++)
|
||
{
|
||
|
||
sprintf_s(Sunname, sizeof(Sunname),"res\\sunshine\\%d.png", suni + 1);
|
||
//"C:\\Users\\URL\\source\\repos\\植物大战僵尸\\植物大战僵尸\\res\\sunshine\\%d.png"
|
||
|
||
loadimage(&imgSun[suni], Sunname);
|
||
|
||
}
|
||
//配置随机种子
|
||
|
||
srand(time(NULL));
|
||
|
||
|
||
//创建游戏图形化窗口
|
||
initgraph(Wiw_width, Wiw_heigh);
|
||
Suncount = 50;//初始阳光的数值
|
||
|
||
|
||
|
||
|
||
}
|
||
//渲染函数,把图片加载出来
|
||
void update_window()
|
||
{
|
||
//BeginBatchDraw函数用于启动批量绘图模式。
|
||
//在这种模式下,所有的绘图操作都不会立即显示在屏幕上,
|
||
//而是暂时存储在内存中,直到调用FlushBatchDraw或EndBatchDraw函数时才会一次性渲染到屏幕上。
|
||
//这种方法可以有效减少绘图过程中的闪烁现象,
|
||
//特别是在动画或连续移动的图形中
|
||
BeginBatchDraw();//开始缓冲
|
||
int i, j, line, cloumn;
|
||
int index, planttype;
|
||
int iS;
|
||
int ballMax;
|
||
putimage(0, 0, &imgBg);
|
||
|
||
putimagePNG(250, 0, &imgToor);
|
||
for (i = 0; i < ZHIWU_COUNT; i++)
|
||
{
|
||
j = 340 + 64 * i;
|
||
putimage(j,6, &imgCards[i]);
|
||
|
||
}
|
||
|
||
//判断是否有植物
|
||
for (line = 0; line < 5; line++)
|
||
{
|
||
for (cloumn = 0; cloumn < 9; cloumn++)
|
||
{
|
||
if (map[line][cloumn].type > 0)
|
||
{
|
||
/*
|
||
line = (msg.y - 70) / 103;//第几行
|
||
column = (msg.x - 250) / 82;//第几列*/
|
||
index = map[line][cloumn].frameIndex;
|
||
planttype = map[line][cloumn].type - 1;
|
||
//可以微调渲染位置
|
||
putimagePNG(250 + cloumn * 82+2, 70 + line * 103+15, imgplt[planttype][index]);
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
//为了使拖动的植物图层在最上面
|
||
// 即拖动时被拖动植物覆盖已经种植的植物
|
||
// 所以将拖动中渲染放到最后
|
||
//渲染拖动中的植物
|
||
if (percent_plant > 0)
|
||
{
|
||
//为了方便定义一个变量img去获取长宽,为了使鼠标指在渲染图片中央
|
||
IMAGE* img = imgplt[percent_plant - 1][0];
|
||
putimagePNG(percentX - img->getwidth() / 2, percentY - img->getheight() / 2, img);
|
||
|
||
|
||
}
|
||
|
||
ballMax = sizeof(balls) / sizeof(balls[0]);
|
||
for (iS = 0; iS < ballMax; iS++)
|
||
{
|
||
if (balls[iS].used)
|
||
{
|
||
IMAGE *img = &imgSun[balls[iS].frameIndex];
|
||
putimagePNG(balls[iS].x, balls[iS].y,img);
|
||
}
|
||
|
||
|
||
}
|
||
EndBatchDraw();//结束双缓冲
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
void collectSun(ExMessage* msg)
|
||
{
|
||
int i;
|
||
for (i = 0; i < sizeof(balls); i++)
|
||
{
|
||
|
||
if (msg->x == balls[i].x && msg->y == balls[i].y)
|
||
{
|
||
Suncount += 50;
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
void userClick()
|
||
{
|
||
//用户鼠标操作交互实现
|
||
//判断有没有消息
|
||
int index;
|
||
int line;
|
||
int column;
|
||
ExMessage msg;
|
||
static int status = 0;//定义静态变量,目的是确保选择后再拖动
|
||
if (peekmessage(&msg))
|
||
{
|
||
if (msg.message == WM_LBUTTONDOWN)
|
||
{
|
||
//判断是否在卡牌区域内操作
|
||
if (msg.x > 340 && msg.x < 340 + 64 * ZHIWU_COUNT && msg.y > 0 && msg.y < 97)
|
||
{
|
||
index = (msg.x - 340) / 64;
|
||
status = 1;
|
||
percent_plant = index + 1;
|
||
//printf("%d\n", index);
|
||
//验证鼠标选择植物卡牌是否准确
|
||
}
|
||
else
|
||
{
|
||
//如果不在卡牌区域内操作,执行以下代码(收集阳光,或铲子回收)
|
||
collectSun(&msg);//可以直接传递msg,但传递一个指针程序消耗少
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
}
|
||
/*
|
||
图片可视化即是渲染,即在窗口某个坐标位置
|
||
出现图片,所以下面代码得用渲染函数处理
|
||
*/
|
||
else if (msg.message == WM_MOUSEMOVE && status == 1)
|
||
{
|
||
percentX = msg.x;
|
||
percentY = msg.y;
|
||
|
||
//拖动过程显示卡牌植物,不是卡牌,进行素材补充
|
||
|
||
//确定哪一种植物,再次添加全局变量status
|
||
|
||
|
||
}
|
||
else if (msg.message == WM_LBUTTONUP)
|
||
{
|
||
|
||
|
||
|
||
line = (msg.y - 70) / 103;//第几行
|
||
column = (msg.x - 250) / 82;//第几列
|
||
//printf("%d%d\n", line+1, column+1);验证种植坐标是否准确
|
||
|
||
//种植位置确定,且确保一个位置只有一个植物
|
||
if (map[line][column].type == 0)
|
||
{
|
||
map[line][column].type = percent_plant;
|
||
map[line][column].frameIndex = 0;
|
||
}
|
||
|
||
|
||
|
||
percent_plant = 0;
|
||
status = 0 ;
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
//创建阳光
|
||
void createSun()
|
||
{
|
||
//控制阳光的刷新频率
|
||
int i;
|
||
static int count = 0;
|
||
static int fre = 1;//400
|
||
count++;
|
||
//每400+帧数刷新一次阳光
|
||
if (count >= 4)
|
||
{
|
||
count = 0;
|
||
fre = 120 + rand() % 200;
|
||
//从阳光池中取一个可以使用的
|
||
|
||
int ballMax = sizeof(balls) / sizeof(balls[0]);
|
||
//找到一个可以使用的阳光球的帧
|
||
for (i = 0; (i <= ballMax) && balls[i].used; i++);
|
||
if (i >= ballMax)
|
||
{
|
||
return;
|
||
}
|
||
|
||
balls[i].used = true;
|
||
balls[i].frameIndex = 0;
|
||
//阳光降落x范围260-930
|
||
balls[i].x = rand() % (900 - 260) + 260;
|
||
|
||
|
||
|
||
//以下代码实现第一个阳光球的x坐标小于345
|
||
static int test = 0;
|
||
if (test == 0)
|
||
{
|
||
balls[i].x = 852;//256
|
||
|
||
test = 1;
|
||
}
|
||
|
||
|
||
//经过以上测试,只要第一个阳光球生成的x坐标<=345,就可以运行下去
|
||
|
||
|
||
//balls[i].x = 345;
|
||
/*
|
||
|
||
经过找错找出
|
||
x坐标大于345出现报错问题
|
||
|
||
|
||
|
||
有阳光会不断在第一个x坐标位置下落一小段距离消失,
|
||
若将x的值小于等于0的阳光会正常下落,但当落下来消失的那一刻会出现报错问题
|
||
|
||
|
||
*/
|
||
|
||
/*
|
||
|
||
问题在第一个阳光上
|
||
1.坐标范围会导致内存冲突什么的
|
||
2.第一个阳光会一直存在不消失
|
||
|
||
|
||
*/
|
||
|
||
|
||
|
||
|
||
|
||
balls[i].y = 60;//阳光的初始位置
|
||
|
||
//阳光的固定落点
|
||
balls[i].fixedY = 200 + (rand() % 4) * 90;
|
||
//balls[i].fixedY = rand() % (560 - 190) + 190;
|
||
balls[i].timer = 0;
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
//阳光位置在竖直向下移动,同时旋转
|
||
void moveSun()
|
||
{
|
||
int i;
|
||
int ballMax = sizeof(balls) / sizeof(balls[0]);
|
||
|
||
for (i = 0; i < ballMax; i++)
|
||
{
|
||
if (balls[i].used)
|
||
{
|
||
//%取余是防止阳光球帧数超出图片数
|
||
balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
|
||
if (balls[i].timer == 0)
|
||
{
|
||
balls[i].y += 4;
|
||
|
||
}
|
||
|
||
if (balls[i].y >= balls[i].fixedY)
|
||
{
|
||
balls[i].timer++;
|
||
//balls[i].used = false;
|
||
if (balls[i].timer >= 100)
|
||
{
|
||
balls[i].used = false;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
void updateGame()
|
||
{
|
||
int i;
|
||
int j;
|
||
int k;
|
||
int planttype;
|
||
int index;
|
||
/*for (k = 0; k< 100000000; k++)
|
||
{
|
||
;
|
||
}*/
|
||
//实现植物摇晃
|
||
for (i = 0; i < 5; i++)
|
||
{
|
||
for (j = 0; j < 9; j++)
|
||
{
|
||
|
||
if (map[i][j].type > 0)
|
||
{
|
||
map[i][j].frameIndex++;
|
||
planttype = map[i][j].type - 1;
|
||
index = map[i][j].frameIndex;
|
||
|
||
if (imgplt[planttype][index] == NULL)
|
||
{
|
||
map[i][j].frameIndex = 0;
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
|
||
//修改游戏数据,即是更新阳光球数据
|
||
|
||
createSun();
|
||
moveSun();
|
||
|
||
|
||
/*
|
||
以上两个函数内容有问题
|
||
|
||
*/
|
||
|
||
|
||
}
|
||
|
||
//初始菜单
|
||
void startUI()
|
||
{
|
||
IMAGE imgSTART,Menu1,Menu2;
|
||
loadimage(&imgSTART, "res\\menu.png");
|
||
loadimage(&Menu1, "res\\menu1.png");
|
||
loadimage(&Menu2, "res\\menu2.png");
|
||
|
||
|
||
//状态变量
|
||
int flag = 0;
|
||
|
||
while (1)
|
||
{
|
||
BeginBatchDraw();
|
||
putimage(0, 0, &imgSTART);
|
||
putimagePNG(460, 120, flag ? &Menu1 : &Menu2);
|
||
|
||
|
||
ExMessage msg;
|
||
if (peekmessage(&msg))
|
||
{
|
||
if (msg.message == WM_LBUTTONDOWN )
|
||
{
|
||
|
||
if (msg.x > 460 && msg.x < 460 + 300 && msg.y>75 && msg.y < 250)
|
||
{
|
||
flag = 1;
|
||
|
||
}
|
||
}
|
||
else if (msg.message == WM_LBUTTONUP&&flag==1)
|
||
{
|
||
//鼠标抬起后进入游戏
|
||
return;
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
}
|
||
EndBatchDraw();
|
||
}
|
||
|
||
|
||
|
||
}
|
||
int main()
|
||
{
|
||
|
||
gameInit();
|
||
startUI();
|
||
int timer = 0;
|
||
bool flag = true;
|
||
while (1)
|
||
{
|
||
|
||
userClick();
|
||
//植物摇摆太快,直接用Sleep();会导致用户点击延迟
|
||
//getDelay();是工具包里的函数,返回值是距离上一次调用的时间差
|
||
//通过以下判断,当时间差大于20ms再进行渲染
|
||
/*下面是实现延迟调用函数的方法
|
||
int getDelay() {
|
||
static unsigned long long lastTime = 0;
|
||
unsigned long long currentTime = GetTickCount();
|
||
if (lastTime == 0) {
|
||
lastTime = currentTime;
|
||
return 0;
|
||
}
|
||
else {
|
||
int ret = currentTime - lastTime;
|
||
lastTime = currentTime;
|
||
return ret;
|
||
}
|
||
}
|
||
*/
|
||
timer += getDelay();
|
||
if (timer > 60)
|
||
{
|
||
flag = true;
|
||
timer = 0;
|
||
|
||
|
||
}
|
||
if (flag)
|
||
{
|
||
flag = false;
|
||
update_window();
|
||
updateGame();
|
||
}
|
||
|
||
|
||
//每运行一次改变游戏内的相关数据,即改变植物图片形成动态效果
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
//system("pause");
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*
|
||
问题
|
||
调试时点击进入游戏之后直接运行结束
|
||
第311行代码&& balls[i].used删掉后问题解决
|
||
即是执行313以下代码导致
|
||
|
||
moveSun();
|
||
|
||
*/ |