C++ 实现俄罗斯方块

一、实验介绍

1.1 实验内容

本节实验我们进行设计俄罗斯方块前的思路分析,以及介绍ncurses 库的使用方法。

1.2 实验知识点

C++ 编程基础

ncurses 库的使用

俄罗斯方块逻辑设计

1.3 实验环境

xfce 终端

g++ 编译器

ncurses 库

1.4 适合人群

本课程难度一般,适合有 C++ 编程基础,对游戏设计、逻辑分析感兴趣的同学。

1.5 代码获取

git clone https://github.com/Gamerchen/game_zero.git

二、开发准备

2.1 安装 ncurses 库

sudo apt-get update

sudo apt-get install libncurses5-dev



2.2 编译程序

编译命令要加上 -l 选项引入 ncurses 库:

g++ main.cpp -l ncurses



三、实验原理

3.1 设计前的分析

在开始程序编写之前,我们要先分析程序设计需要实现哪些功能,划分为哪些模块,在俄罗斯方块中我们首先想到的应该是显示方块,其次是方块的下落,左右移动,旋转,最后的层满消行,另外一个基本的俄罗斯方块游戏还应该有下一个方块形状的提示功能。

所以我们编程中需要解决的问题有:

显示方块

实现方块的移动

方块旋转

对层满的方块消行

提示下一个方块形状

3.2 基本图形

每个方块由四个 box 组成,从游戏框的中心位置掉落,在框内不碰撞边界和其他方块的情况下可以进行旋转。

3.3 NCURSES库的使用

简单地说,NCURSES 是一个从 System V Release 4.0 (SVr4) 中 CURSES 的克隆,这是一个可自由配置的库,完全兼容旧版本的 CURSES,是一个可以使应用程序直接控制终端屏幕显示的库。NCURSES封装了底层的终端功能,包含了一些创建窗口的函数,并且有Menu、Panel 和 Form对CURSES基础库的扩展,我们可以建立一个同时包含多窗口(multiple windows)、菜单(menus)、面板(panels)和表单(forms)的应用程序。窗口可以被独立管理,例如让它卷动(scrollability)或者隐藏。 菜单(Menus)可以让用户建立命令选项,从而方便执行命令。而窗体(Forms)允许用户建立一些简单的数据输入和显示的窗口。面板(Panels)是 NCURSES 窗口管理功能的扩展,可以用它覆盖或堆积窗口。

3.3.1 NCURSES--从Hello World程序开始

如果调用 NCURSES 库中的函数,必须在代码中加载 ncurses.h 文件( ncurses.h中已经包含stdio.h ) 例:

#include <ncurses.h>

int main()
{
initscr(); //初始化,进入NCURSES模式
printw("Hello World!"); //在虚拟屏幕上打印 Hello Wowrld!
refresh(); //将虚拟屏幕上的内容写到显示器上,并刷新
getch(); //等待用户输入
endwin(); //退出NCURSES模式
return 0;
}

在以上实例中我们介绍了 NCURSES 库中最基本函数的使用方法,函数的功能已在注释中说明,这里不再赘述。

3.3.2 窗口机制

当 NCURSES 初始化的时候,它会默认创建一个叫做 stdscr 的窗口,大小一般是 80 列,25 行(根据显示器或者显卡的不同,可能会出现不同的大小),除此之外,你还可以通过窗口系统的函数创建你自己的窗口。 举例说明,如果调用以下函数:

printw("Hi!");

refresh();



它会在stdscr上当前光标位置输出 "Hi!",调用 refresh() 函数,只更新 stdscr 上的缓冲区。

如果你已经建立了一个叫做win的窗口,想要在win窗口上输出内容,可以再普通函数前添加w,同时参数也要发生变化。

printw(string) //在stdscr的当前光标位置打印字符串string

mvprintw(y,x,string) //将字符串string打印在坐标(y,x)处

wprintw(win,string) //在窗口win的当前光标位置打印字符串string

mvwprintw(win,y,x,string) //将光标移动到窗口win的(y,x)处然后打印字符串string



相信看完上面的例子,你已经能够通过函数的命名规则看出各个函数的功能区别

3.3.3 newwin和box函数

一个窗口的建立是通过 newwin() 函数开始的,函数返回一个指向窗口的结构指针,这个指针可以被传送至一些类似于 wprintw() 这样需要窗口参数的函数中。 然而,我们创建了一个窗口却无法看见它,需要用 box() 函数在已经定义的窗口外围画上边框。 例:

WINDOW *create_newwin(int height, int width, int starty, int startx)

{

WINDOW *local_win;

local_win = newin(height, width, starty, startx);

box(local_win, 0, 0);

wrefresh(local_win);

return local_win;

}



关于 NCURSES 库的基本使用方法就介绍到这里了,在具体使用中遇到问题仍需要查阅相关资料。

c++实现俄罗斯方块代码

#include <iostream>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <ncurses.h>
#include <unistd.h>

using namespace std;

void swap(int &a, int &b){
int t=a;
a = b;
b = t;
}
int getrand(int min, int max)
{
return(min+rand()%(max-min+1));
}

WINDOW *create_newwin(int height,int width,int starty,int startx);
void destory_win(WINDOW *local_win);

int game_win_height=30;
int game_win_width=45;

int hint_win_height=10;
int hint_win_width=20;
WINDOW * game_win, *hint_win ,*score_win;
int key;

class Piece
{
public:
int score;
int shape;
int next_shape;

int head_x;
int head_y;

int size_h;
int size_w;

int next_size_h;
int next_size_w;

int box_shape[4][4];
int next_box_shape[4][4];

int box_map[30][45];

bool game_over;

public:
void initial();
void set_shape(int &cshape, int box_shape[][4],int &size_w, int & size_h);

void score_next();
void judge();
void move();
void rotate();
bool isaggin();
bool exsqr(int row);
​ };

int main()
{

initscr();
//raw();
cbreak();
noecho();
curs_set(0);
keypad(stdscr,TRUE);

refresh(); game_win = create_newwin(game_win_height, game_win_width, 0,0);
wborder(game_win, '*', '*', '*', '*', '*', '*', '*', '*');
wrefresh(game_win);

hint_win = create_newwin(hint_win_height, hint_win_width, 0, game_win_width+10);
mvprintw(0, game_win_width+10+2,"%s","Next");
refresh();

score_win = create_newwin(hint_win_height, hint_win_width, 20, game_win_width+10);
mvprintw(20, game_win_width+10+2,"%s","Score");
refresh();



Piece* pp = new Piece;
pp->initial();


while(1)
{
pp->move();
if(pp->game_over)
break;
}

destory_win(game_win);
destory_win(hint_win);
destory_win(score_win);
delete pp;
system("clear");

int row,col;
getmaxyx(stdscr,row,col);
mvprintw(row/2,col/2 ,"%s","GAMER OVER ! \n ");
mvprintw(row/2+2,col/2-2 ,"%s","Wait 5s to return tthe erminal ! \n ");
refresh();

sleep(5);
endwin();
return 0;
}

WINDOW *create_newwin(int height, int width, int starty, int startx)
{
WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
box(local_win,0,0);
wrefresh(local_win);
return local_win;
}

void destory_win(WINDOW *local_win)
{
wborder(local_win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
wrefresh(local_win);
delwin(local_win);
}


void Piece::initial()
{
score=0;
game_over=false;
for(int i =0;i<game_win_height;i++)
for(int j=0;j<game_win_width;j++){
if(i==0 || i==game_win_height-1 || j==0 || j==game_win_width-1){
box_map[i][j]=1;
}
else
box_map[i][j]=0;
}

srand((unsigned)time(0));
shape=getrand(0,6);
set_shape(shape,box_shape,size_w,size_h);

next_shape=getrand(0,6);
set_shape(next_shape,next_box_shape,next_size_w,next_size_h);

for(int i =0;i<4;i++)
for(int j=0;j<4;j++)
if(next_box_shape[i][j]==1){
mvwaddch(hint_win,(hint_win_height-size_h)/2+i,(hint_win_width-size_w)/2+j,'#');
wrefresh(hint_win);
} ​
mvwprintw(score_win, hint_win_height/2,hint_win_width/2-2,"%d",score);
wrefresh(score_win);
}

void Piece::set_shape(int &cshape, int shape[][4],int &size_w,int &size_h)
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
shape[i][j]=0;
switch(cshape)
{
case 0:
size_h=1;
size_w=4;
shape[0][0]=1;
shape[0][1]=1;
shape[0][2]=1;
shape[0][3]=1;
break;
case 1:
size_h=2;
size_w=3;
shape[0][0]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
break;
case 2:
size_h=2;
size_w=3;
shape[0][2]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
break;
case 3:
size_h=2;
size_w=3;
shape[0][1]=1;
shape[0][2]=1;
shape[1][0]=1;
shape[1][1]=1;
break;

case 4:
size_h=2;
size_w=3;
shape[0][0]=1;
shape[0][1]=1;
shape[1][1]=1;
shape[1][2]=1;
break;

case 5:
size_h=2;
size_w=2;
shape[0][0]=1;
shape[0][1]=1;
shape[1][0]=1;
shape[1][1]=1;
break;

case 6:
size_h=2;
size_w=3;
shape[0][1]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
break;
}

head_x=game_win_width/2;
head_y=1;

if(isaggin()) /* GAME OVER ! */
game_over=true;

}


void Piece::rotate()
{
int temp[4][4]={0};
int temp_piece[4][4]={0};
int i,j,tmp_size_h,tmp_size_w;

tmp_size_w=size_w;
tmp_size_h=size_h;

for(int i=0; i<4;i++)
for(int j=0;j<4;j++)
temp_piece[i][j]=box_shape[i][j];


for(i=0;i<4;i++)
for(j=0;j<4;j++)
temp[j][i]=box_shape[i][j];
i=size_h;
size_h=size_w;
size_w=i;
for(i=0;i<size_h;i++)
for(j=0;j<size_w;j++)
box_shape[i][size_w-1-j]=temp[i][j];


if(isaggin()){
for(int i=0; i<4;i++)
for(int j=0;j<4;j++)
box_shape[i][j]=temp_piece[i][j];
size_w=tmp_size_w;
size_h=tmp_size_h;
}
else{
for(int i=0; i<4;i++)
for(int j=0;j<4;j++){
if(temp_piece[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j,' ');
wrefresh(game_win);
}
}
for(int i=0; i<size_h;i++)
for(int j=0;j<size_w;j++){
if(this->box_shape[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j,'#');
wrefresh(game_win);
}
}

}
}

void Piece::move(){
fd_set set;
FD_ZERO(&set);
FD_SET(0, &set); struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec= 500000; if (select(1, &set, NULL, NULL, &timeout) == 0){
head_y++;
if(isaggin()){
head_y--;
for(int i=0;i<size_h;i++)
for(int j=0;j<size_w;j++)
if(box_shape[i][j]==1)
box_map[head_y+i][head_x+j]=1;
score_next();
}
else{
for(int i=size_h-1; i>=0;i--)
for(int j=0;j<size_w;j++){
if(this->box_shape[i][j]==1){
mvwaddch(game_win,head_y-1+i,head_x+j,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');

}
}
wrefresh(game_win);
}

} if (FD_ISSET(0, &set)) {
while ((key = getch()) == -1) ;

if(key==KEY_LEFT){
head_x--;
if(isaggin())
head_x++; //undo
else{
for(int i=0; i<size_h;i++)
for(int j=0;j<size_w;j++){
if(this->box_shape[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j+1,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');

}
}
wrefresh(game_win);
}
}

if(key==KEY_RIGHT){
head_x++;
if(isaggin())
head_x--;
else{
for(int i=0; i<size_h;i++)
for(int j=size_w-1;j>=0;j--){
if(this->box_shape[i][j]==1){
mvwaddch(game_win,head_y+i,head_x+j-1,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');

}
}
wrefresh(game_win);
}
}

if(key==KEY_DOWN){
head_y++;
if(isaggin()){
head_y--;
for(int i=0;i<size_h;i++)
for(int j=0;j<size_w;j++)
if(box_shape[i][j]==1)
box_map[head_y+i][head_x+j]=1;

score_next(); }
else{
for(int i=size_h-1; i>=0;i--)
for(int j=0;j<size_w;j++){
if(this->box_shape[i][j]==1){
mvwaddch(game_win,head_y-1+i,head_x+j,' ');
mvwaddch(game_win,head_y+i,head_x+j,'#');

}
}
wrefresh(game_win);
}
}

if(key==KEY_UP)
rotate();

if(head_x+size_w+1>game_win_width)
head_x=game_win_width-size_w-1;
if(head_x<1)
head_x=1;
}
}

bool Piece::isaggin(){
for(int i=0;i<size_h;i++)
for(int j=0;j<size_w;j++){
if(box_shape[i][j]==1){
if(head_y+i > game_win_height-2)
return true;
if(head_x+j > game_win_width-2 || head_x+i-1<0)
return true;
if(box_map[head_y+i][head_x+j]==1)
return true ;
}
}
return false;
}

bool Piece::exsqr(int row){
for(int j=1;j<game_win_width-1;j++)
if(box_map[row][j]==1)
return true;
return false;
}

void Piece::judge(){
int i,j;
int line=0;
bool full;
for(i=1;i<game_win_height-1;i++){
full=true;
for(j=1;j<game_win_width-1;j++){
if(box_map[i][j]==0)
full=false;
}
if(full){
line++;
score+=50;
for(j=1;j<game_win_width-1;j++)
box_map[i][j]=0;
}
}
if(line!=0){
for(i=game_win_height-2;i>=2;i--){
int s=i;
if(exsqr(i)==0){
while(s>1 && exsqr(--s)==0);
for(j=1;j<game_win_width-1;j++){
box_map[i][j]=box_map[s][j];
box_map[s][j]=0;
}
}
}

for(int i=1;i<game_win_height-1;i++)
for(int j=1;j<game_win_width-1;j++){
if(box_map[i][j]==1){
mvwaddch(game_win,i,j,'#');
wrefresh(game_win);
}
else{
mvwaddch(game_win,i,j,' ');
wrefresh(game_win);
}
}
}
}

void Piece::score_next(){
score+=10;
judge();

mvwprintw(score_win, hint_win_height/2,hint_win_width/2-2,"%d",score);
wrefresh(score_win);


set_shape(next_shape,box_shape,size_w,size_h);

this->next_shape=getrand(0,6);
set_shape(next_shape,next_box_shape,next_size_w,next_size_h);


for(int i =1;i<hint_win_height-1;i++)
for(int j=1;j<hint_win_width-1;j++){
mvwaddch(hint_win, i, j,' ');
wrefresh(hint_win);
}
for(int i =0;i<4;i++)
for(int j=0;j<4;j++)
if(next_box_shape[i][j]==1){
mvwaddch(hint_win,(hint_win_height-size_h)/2+i,(hint_win_width-size_w)/2+j,'#');
wrefresh(hint_win);
}
}

运行如下 有点low 基本功能都有

运行结果.jpg

C++ 实现俄罗斯方块的更多相关文章

  1. 还是俄罗斯方块之android版

    前面的,口水话 请直接跳过. 虽然现在不比以前了 也没多少人气了,放到首页 都不到几百的点击量.也许博客园整体水平也是在往水的方向发展.不谈那些了,哥也曾经辉煌过 有过一天上千的点击量 ,哥也曾经有过 ...

  2. x01.Tetris: 俄罗斯方块

    最强大脑有个小孩玩俄罗斯方块游戏神乎其技,那么,就写一个吧,玩玩而已. 由于逻辑简单,又作了一些简化,所以代码并不多. using System; using System.Collections.G ...

  3. 俄罗斯方块C#版

    using System; using System.Windows.Forms; using System.Drawing; using System.Media; class me : Form ...

  4. 纯JS实现俄罗斯方块,打造属于你的游戏帝国

    纯JS俄罗斯方块,打造属于你的游戏帝国. 本文原始作者博客 http://www.cnblogs.com/toutou 俄罗斯方块(Tetris, 俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏 ...

  5. 用纯JS做俄罗斯方块 - 简要思路介绍(1)

    大家都知道俄罗斯方块是一款大众化的游戏了,我很小的时候就玩过,今年已经25岁了,可以说俄罗斯方块确实是历史悠久,做俄罗斯方块是我上个星期开始的想法.也许是由于自己从来没有写过这种东西吧,所以有生疏.代 ...

  6. 趣味python编程之经典俄罗斯方块

    国庆期间闲不住,用python把经典俄罗斯方块实现了一遍,找到了些儿时的乐趣.因此突发奇想,打算用python写点经典又确实有趣的小程序形成系列.正统编程之余也给自己找点儿乐趣,换个角度写程序. 原计 ...

  7. javascript俄罗斯方块游戏

    在线试玩:http://keleyi.com/game/5/ 操作指南:键盘方向键←→控制左右移动,↑键变形,↓键快速下落. 别看这段js代码只有短短的100多行,效果却非常不错,用键盘的方向键操作, ...

  8. 俄罗斯方块(Win32实现,Codeblocks+GCC编译)

    缘起: 在玩Codeblocks自带的俄罗斯方块时觉得不错,然而有时间限制.所以想自己再写一个. 程序效果: 主要内容: 程序中有一个board数组,其中有要显示的部分,也有不显示的部分,不显示的部分 ...

  9. CCF 201604-2 俄罗斯方块

    题目不难,但是感觉很有意思.一开始忘了把调试信息注释掉,WA了两次... 试题编号: 201604-2 试题名称: 俄罗斯方块 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 ...

  10. Javascript 俄罗斯方块 游戏代码解释!

    俄罗斯方块代码说明 /** 名称:Javascript 俄罗斯方块! 作者:Gloot 邮箱:glootz@gmail.com QQ:345268267 网站:http://www.cnblogs.c ...

随机推荐

  1. 通过wget工具下载指定文件中的URLs对应的资源并保存到指定的本地目录中去并进行文件完整性与可靠性校验

    创建URLs文件在终端输入cd target_directory回车,便把当前文件夹切换到了目标文件夹target_directory,此后创建的文件都会丢它里面在终端输入cat > URLs回 ...

  2. 理解JavaScript中函数方法

    1.函数声明和函数表达式 通过字面量创建函数的方式有两种函数声明和函数表达式: 函数声明: function sum(x, y) { var result = x + y; return result ...

  3. 改变textField的placeholder的颜色和位置

    重写UItextField的这个方法,用其他的textField继承自这个父类 - (void) drawPlaceholderInRect:(CGRect)rect { [[UIColor blue ...

  4. Python基础-用户验证

    一.项目需求 1.根据用户名和密码,验证用户是否可登陆 2.允许一次执行可验证三次 3.当用户名输错三次后,该用户名锁定,永久不可登陆 二.代码如下 #!/usr/bin/env python #-* ...

  5. uvalive 3635 Pie

    https://vjudge.net/problem/UVALive-3635 题意: 有F+1个人要分n个蛋糕,他们得到的蛋糕的面积必须是一样的,但是每个蛋糕必须是整块的蛋糕,而不是有多块蛋糕拼成的 ...

  6. Python系列之 - 反射

    一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静态方法:让类里的方法直接被 ...

  7. c语言一个显示星号的函数(隐藏密码)

    显示星号 void star(char p[])    //显示星号 {     int j; while((p[j] = getch())!='\r') { if(p[j] !='\b') { pr ...

  8. Menu-右键弹出菜单

    #右键弹出菜单 from tkinter import * root=Tk() def callback(): print('我被调用了') menubar =Menu(root) menubar.a ...

  9. Mysql之数据类型(胖胖老师)

    like语句与通配符insert into teacher_1 values('胖胖', '男', 18),('小明', '男', 19),('张三', '男', 30),('李四', '男', 27 ...

  10. 百度API-------热力图

    <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...