标签:目录 layer 预编译 交流 inf 个人 间隔 通过 vscode
|--------------------项目GitHub地址--------------------|
玩家地图map
碰撞检测:
bool Player::detectCollision(Block block, int x, int y) {
//发生碰撞返回false
//未发生返回true
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
// 如果检测到block中该位置为1的话
// 先检测这个位置是否越界
// 再检测这个位置对应的map位置是否也为1
if(block.block[i][j]==1) {
if(x + i >= 20 || y + j < 0 || y + j >= 10) {
return false;
}
else if(map[x+i][y+j]==1 && x + i >=0) {
return false;
}
}
}
}
return true;
}
玩家方块管理
旋转:利用tempBlock标记,如果旋转后不会碰撞,则保持不变,如果旋转后碰撞则将tempBlock赋值回去
左移、右移:利用碰撞检测去检测移动后pos定位点,实现同旋转。
下移:检测同左移右移,如果发生碰撞就执行map的更新操作,如果发生碰撞需返回true,代表发生碰撞
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
if(posX + i >= 0 && posY + j >= 0 && posX + i < 20 && posY + j < 10 && blockNow.block[i][j] == 1) {
map[posX+i][posY+j]=1;
}
}
}
管理用户信息如名字,得分
检测消行:检测每一行,如果满足消行,则将该行上面方块向下移动一格,在结尾返回消去的行数,方便双人模式下此消彼长
int Player::detectReductsion() {
// 记录消去的行数
int count = 0;
for(int i = 0; i < 20; i++) {
// 记录单行的方块个数
int tempcount = 0;
for(int j = 0; j < 10; j++) {
if(map[i][j] == 1) {
tempcount++;
}
}
if(tempcount >= 10) {
// 增加分数
point+=10;
// 增加消除行数
count++;
// 移动上面的行
for(int k=i;k>=1;k--) {
for(int j=0;j<10;j++) {
map[k][j]=map[k-1][j];
}
}
}
}
return count;
}
方块增加:接受一个int类型传参,利用for循环每次在底部增加一行,在增加前先检测map顶部,是否游戏结束
bool Player::addBlock(int num) {
for(int i=0;i<num;i++) {
for(int t=0;t<10;t++) {
if(map[0][t]>0) {
fail = true;
return false;
}
}
// 移动下面行
for(int m=0; m<19; m++) {
for(int n=0; n<10; n++) {
map[m][n] = map[m+1][n];
}
}
// 底部清零
for(int j=0; j<10; j++) {
map[19][j] = 0;
}
// 底部随机增加
for(int j=0; j<10; j++) {
map[19][rand()%10]++;
}
for(int j=0; j<10; j++) {
if(map[19][j]) {
map[19][j]=1;
}
}
}
return true;
}
玩家状态更新
私有成员:itfs -> Interface类的实例化,用于Game的渲染
游戏控制:控制游戏进程,包括模式选择,名字输入,游戏结束是否重新开始
游戏模式选择
int Game::selectGameType() {
// 渲染
itfs.selectPart();
itfs.selectKey1();
int type=1;
while(1) {
if(_kbhit()){
int key=_getch();
if(key==72&&type!=1){
itfs.selectKey1();
type=1;
}
if(key==80&&type!=2){
itfs.selectKey2();
type=2;
}
if(key==13){
return type;
}
}
}
}
单人模式:速度控制,每秒检测50次键盘输入
// speed = 50
void Game::onePlayer(Player player) {
// 页面渲染
while(1) {
if(_kbhit()) {
int key=_getch();
if(key==115) {
// S键
if(方块下落) {
if(检测消行) {
// 渲染失败页面
// 返回
}
// 更新方块和map
}
}
else if(key==119) {
// W键
// 旋转
}
else if(key==97) {
// A键
// 左移
}
else if(key==100) {
// D键
// 右移
}
else if(key == 32) {
// 暂停处理
}
if(有消行) {
// 清除map区域
// 更新方块
// 更新map
// 更新分数
}
else {
// 更新方块
}
}
Sleep(20);
if(--temptime == 0) {
if(方块下落) {
if(检测消行) {
// 渲染失败页面
// 返回
}
// 更新方块和map
}
if(有消行) {
// 清除map区域
// 更新方块
// 更新map
// 更新分数
}
else {
// 更新方块
}
temptime = speed;
}
}
}
双人模式:参考单人模式代码,增加在检测消行处增加方块增加功能
int add1 = player1.detectReductsion();
int add2 = player2.detectReductsion();
// 如果有消行,此消彼长,检测玩家2是否失败
if(add1) {
if(!player2.addBlock(add1)) {
// 失败渲染
itfs.gameResult(player1.getName(), player1.getPoint(), 1);
return;
}
itfs.printPointPlayer1(player1.getPoint());
}
// 如果没有,正常渲染玩家1的方块
else {
itfs.deleteBlock1();
itfs.drawNowBlock1(player1.getNowBlock(), player1.getX(), player1.getY());
itfs.refreshBlock1(player1.getX(), player1.getY(), player1.getNowBlock());
}
// 如果有消行,此消彼长,检测玩家1是否失败
if(add2) {
if(!player1.addBlock(add2)) {
// 失败渲染
itfs.gameResult(player2.getName(), player2.getPoint(), 1);
return;
}
itfs.printPointPlayer2(player2.getPoint());
}
// 如果没有,正常渲染玩家2的方块
else {
itfs.deleteBlock2();
itfs.drawNowBlock2(player2.getNowBlock(), player2.getX(), player2.getY());
itfs.refreshBlock2(player2.getX(), player2.getY(), player2.getNowBlock());
}
// 如果任何一个人有消行就重新渲染map
if(add1 != 0 || add2 != 0) {
itfs.clearMap1(player1.map);
itfs.printMap1(player1.map);
itfs.drawNowBlock1(player1.getNowBlock(), player1.getX(), player1.getY());
itfs.clearMap2(player2.map);
itfs.printMap2(player2.map);
itfs.drawNowBlock2(player2.getNowBlock(), player2.getX(), player2.getY());
}
由图可见,block被重复包含,所以在编译时会报错,需要用到预编译知识
在Block处定义_BLOCK,用于判断是否已经包含Block类
/*-----------block.h-----------*/
#define _BLOCK
/*-----------player.h----------*/
#ifndef _BLOCK
#include "block.h"
#endif
/*----------interface.h--------*/
#ifndef _BLOCK
#include"block.h"
#endif
这样不会导致Block类在多处被定义
在完成检测碰撞的测试时,在一个不起眼的地方数组发生了越界。我请求了团队的另外两个人一起查看,由于其中一个人使用的是32位虚拟机,所以在编译时需加上-m32
参数。然而在我这运行程序会出现问题,但是在32位虚拟机上却可以正常运行。这一结果导致思考方向偏离了原先正确的思路,开始相信自己代码没有存在问题,经过一段时间后,最终发现问题在于数组越界,但是这也值得思考32位和64位电脑对于数组越界的检查上的差异。
在两个多星期之前,尝试过完成检测游戏是否失败的功能,但是在中间一段时间没有去处理该文件,后来对于功能的实现上的思路转变,导致渐渐淡忘这段不起眼的代码,再后来,将代码拼凑起来后,出现问题,却迟迟找不到错误,花费大量时间,最后通过不断测试输出,找到bug。
在每次方块移动,消行,方块碰撞之后都需要渲染新的页面,开始采用的较为简单的,将页面全部清除,再重新渲染,但是会造成页面闪烁的问题,原因是由于清除的打印中间短暂的间隔,使得看上去好像屏幕在闪烁。为了解决这个问题,和负责渲染部分的队友讨论过后,认为只有在消行情况下需要重新渲染整个页面,其他情况下则可部分渲染,只对原先页面的的一小部分改动的地方进行清除和重新渲染,这样可以解决屏幕闪烁的问题,提高了用户的体验。
关于双人模式下,键盘输入采用_kbhit()函数监听会导致按键发生冲突,当一个人按住键盘不动时,两个人的按键输入都会受到影响,目前还没有较好的解决办法。
思路:多线程、更好的输入函数
代码还不够简洁,关于game类还可以将一些功能进行拆分;在游戏重新开始的实现上采用了goto语句,不是很好。
标签:目录 layer 预编译 交流 inf 个人 间隔 通过 vscode
原文地址:https://www.cnblogs.com/JoshuaYu/p/13095877.html