|
首先,感谢:林耿亮老师,可搜公众号:你好编程。C语言学习最好的兴趣教材。
其次,本文是我学完并手动输入完成飞机大战的复盘内容。比较零散,仅作为我的复习笔记。
一、基本知识与技能。
1、作为游戏,肯定离不开图形和声音。建议使用easyx图形库。网址:http://www.easyx.cn。
涉及基本图形的绘制,形状的样式、颜色的设置,形状的剪贴。
涉及基本图形及图片的运动,碰撞处理。
涉及游戏中键盘、鼠标的控制及交互处理。
涉及图片的加载,前景与背景图片的融合。
涉及批量绘图及图片显示的精确帧率控制。
涉及游戏中文字内容的显示,设置。
涉及游戏音频的调用,控制。多个音频实例的复用。
2、掌握C语言基础知识,程序结构、熟练循环、判断语句的使用。
面向对象的程序涉及,通过结构体构建面向对象风格。
指针的使用,参数的含义。
数组的使用,及动态数组的构建。
3、掌握常见头文件的内容,库文件的使用,相关编译器的设置及程序调试。
二、主要使用的头文件,库文件;编译器设置。
1、头文件
easyx.h
stdio.h
stdlib.h
stdint.h
math.h
time.h
windows.h
2、库文件,winmm.lib。工程-属性-链接器-输入-附加依赖项,添加。库winmm.lib。
3、编译报警设置,(C4996错误)。
工程,预处理器,屏蔽错误_CRT_SECURE_NO_WARNINGS;
使用安全函数;
工程,配置属性,c/c++,高级,禁用特定警告;
4、字符集设置,多字节字符。需要修改:项目名称-属性-配置属性-高级-字符集=未设置。
三、飞机大战程序结构

四、程序实现
1、图像融合文件,包括image.h文件:
#pragma once
#include <easyx.h>//引用图形库
void putTransparentImage(int x, int y, const IMAGE* mask, const IMAGE* img);//对应cpp文件函数
image.app文件:
#include &#34;image.h&#34;
//函数为图片背景透明化,easyx功能。采用位运算。
void putTransparentImage(int x, int y, const IMAGE* mask, const IMAGE* img)
{
putimage(x, y, mask, SRCAND);
putimage(x, y, img, SRCPAINT);
}
2、通用动态数组,包括两个文件,vector.h和vector.cpp文件。
vector.h头文件:
#pragma once
#define VECTOR_INIT_CAPACITY 10//定义常量,vector_init_capacity,表示初始数组大小,10;
struct vector {
bool (*append)(struct vector* pVec, void* data);//追加数据方法
void* (*get)(struct vector* pVec, int index);//获取数据方法
void (*clear)(struct vector *pVec);//清除全部数据方法
void (*remove)(struct vector* pVec, int index);//删除一条数据方法
void **pData;//二级指针,关于游戏元素结构体的首地址,为啥是二级指针,理解中。
int size;//结构体数组存储数据数量;
int capacity;//动态数组空间大小;
};
void vectorInit(struct vector*);//动态数组初始化函数;
void vectorDestroy(struct vector* pVec);//动态数组销毁函数;
vector.cpp文件:
#include &#34;vector.h&#34;//引用
#include <stdlib.h>//malloc,realloc,动态数组
//追加数据函数
bool vectorAppend(struct vector* pVec, void *data)//结构体指针传入
{
if (pVec == NULL || data == NULL)//判空
return false;
// 数据超过数组长度
if (pVec->size >= pVec->capacity)
{
// 加长到两倍,二级指针newdata,二级指针pvec->pdata。理解中。
void ** newData = (void **)realloc(pVec->pData, pVec->capacity * sizeof(void *) * 2);//2倍增加
if (newData == NULL)//判空
{
return false;
}
pVec->pData = newData;//赋值新指针
pVec->capacity = 2 * pVec->capacity;
}
pVec->pData[pVec->size] = data;//将传入的结构体内容,赋值pData[]数组,pData是指针。
pVec->size++;
return true;
}
void* vectorGet(struct vector* pVec, int index)//读取一条记录内容
{
if (index >= pVec->size)//记录号大于记录条数。
return NULL;
return pVec->pData[index];//返回一条记录内容
}
void vectorRemove(struct vector* pVec, int index)//删除一条记录内容
{
for (int i = index; i < pVec->size - 1; i++)//数据依次移动覆盖前一数据。
pVec->pData = pVec->pData[i + 1];
pVec->size -= 1;//记录数量减一。
}
void vectorClear(struct vector* pVec)//清查全部记录
{
if (pVec->pData != NULL)//数据不为空,释放数据空间。
free(pVec->pData);
//以下重新初始化。
pVec->pData = (void**)malloc(sizeof(void*) * VECTOR_INIT_CAPACITY);
pVec->capacity = VECTOR_INIT_CAPACITY;
pVec->size = 0;
}
void vectorInit(struct vector* pVec)//动态数组初始化
{
pVec->get = vectorGet;
pVec->append = vectorAppend;
pVec->remove = vectorRemove;
pVec->clear = vectorClear;//以上是四个方法的声明
// 初始情况下申请VECTOR_INIT_CAPACITY个element
pVec->pData = (void**)malloc(sizeof(void*) * VECTOR_INIT_CAPACITY);
pVec->capacity = VECTOR_INIT_CAPACITY;
pVec->size = 0;
}
void vectorDestroy(struct vector* pVec)//销毁数组
{
if (pVec->pData == NULL)
return;
free(pVec->pData);//释放空间
pVec->pData = NULL;
pVec->size = 0;
pVec->capacity = 0;
3、声音播放处理,soundmanager.h文件
#pragma once
#include &#34;vector.h&#34;//动态数组头文件
struct soundManager {//定义结构体,声音播放,关闭,两个函数,
void (*play)(struct soundManager*);
void (*close)(struct soundManager* e, int interval);
vector vecSoundAlias;//声音别名
char soundPath[100];//声音路径
};
void soundManagerInit(struct soundManager*, const char *);//初始化
void soundManagerDestroy(struct soundManager*);//销毁
soundmanager.cpp文件:
#include &#34;soundmanager.h&#34;
#include <stdlib.h>
#include <stdio.h>
#include <easyx.h>
#include <time.h>
#include <stdint.h>
#include <Windows.h>
void soundPlay(struct soundManager *e)
{
int currentTime = GetTickCount();
int* pAlias = (int*)malloc(sizeof(int));
if (pAlias == NULL)
return;
*pAlias = currentTime;
e->vecSoundAlias.append(&e->vecSoundAlias, pAlias);
char command[100];
sprintf(command, &#34;open %s alias %d&#34;, e->soundPath, currentTime);
mciSendString(command, NULL, 0, NULL);
sprintf(command, &#34;play %d&#34;, currentTime);
mciSendString(command, NULL, 0, NULL);
}
void soundClose(struct soundManager *e, int interval)
{
int currentTime = GetTickCount();
char command[100];
for (int i = 0; i < e->vecSoundAlias.size; i++)
{
int* pAlias = (int*)e->vecSoundAlias.get(&e->vecSoundAlias, i);
if (currentTime - *pAlias < interval)
continue;
sprintf(command, &#34;close %d&#34;, *pAlias);
mciSendString(command, NULL, 0, NULL);
free(pAlias);
e->vecSoundAlias.remove(&e->vecSoundAlias, i);
i--;
}
}
void soundManagerInit(struct soundManager*e, const char *soundPath)
{
e->play = soundPlay;
e->close = soundClose;
vectorInit(&e->vecSoundAlias);
strcpy(e->soundPath, soundPath);
}
void soundManagerDestroy(struct soundManager* e)
{
char command[100];
for (int i = 0; i < e->vecSoundAlias.size; i++)
{
int*pAlias = (int*)e->vecSoundAlias.get(&e->vecSoundAlias, i);
sprintf(command, &#34;close %d&#34;, *pAlias);
mciSendString(command, NULL, 0, NULL);
free(pAlias);
}
vectorDestroy(&e->vecSoundAlias);
} |
|