搜索
bottom↓
回复: 159

独立自主弄的 俄罗斯方块 ,给大家瞧瞧

[复制链接]

出0入0汤圆

发表于 2008-5-8 19:48:01 | 显示全部楼层 |阅读模式
我又来了,还是5110液晶

弄了几天,把俄罗斯方块程序编了个大概

游戏区是18*15格,3*3点阵一格,右边有下一个图形显示和所消行数的显示

没弄随机数,反正伪随机也没啥意思,只是打乱个顺序,每次随机出来的结果都一样,还不如直接出来下一个图形。

没有做暂停(很简单,只要把定时器暂停一下,把除恢复游戏按扭屏蔽了),我的板子上只有3个键,无奈没有做加速下移(其实很简单,当下移键按下不放时,每次下移2格,放开,就还原到每次下移一格),没有做游戏结束判断(同样很简单,只要检查第一行是不是有图形,新生成的不算),由于按键不是中断的,所以浪费时间扫描,感觉有点响应慢,不过没关系,功能都已经做到了

下面贴图:


(原文件名:1.jpg)
这个是有一个停留在底下了,新的还在动。

(原文件名:2.jpg)
“土”字型的被挡在L型的上面停住了

(原文件名:3.jpg)
消了一行以后,line的数字变成了“001”

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2008-5-8 19:56:20 | 显示全部楼层
希望LZ来这能共享一点,而不仅仅是炫耀下就闪人。。。。。。。。

出0入0汤圆

 楼主| 发表于 2008-5-8 20:20:35 | 显示全部楼层
这么没耐心

刚刚在拍视频呢,呵呵,这年头似乎流行视频啊,哈哈

视频在这里,程序后面会有,还会写思路:

数码相机拍的,mov格式,可以用暴风影音打开
点击此处下载 ourdev_271062.rar(文件大小:20.37M) (原文件名:PICT4612.rar)

出0入0汤圆

发表于 2008-5-8 20:31:40 | 显示全部楼层
这个要顶~

总以为3310的屏很小,看来还凑或

出0入0汤圆

发表于 2008-5-8 20:34:56 | 显示全部楼层
确实不错,楼主弄这玩意儿肯定消耗了不少脑细胞。有个疑问,楼主有这能力和时间,接点项目不是比搞这个即无创新,又无价值的游戏更好吗?

出0入0汤圆

发表于 2008-5-8 20:37:16 | 显示全部楼层
楼主多接项目,也不会成为头像上那么惨的样子了啦,哈哈!

出0入0汤圆

发表于 2008-5-8 20:40:15 | 显示全部楼层
to 【4楼】 ecat 电子猫
    这个工作与爱好的关系

出0入0汤圆

 楼主| 发表于 2008-5-8 20:45:15 | 显示全部楼层
这个是主函数:

void main(void)
{
    unsigned char i;
    keyInit();
        Delay(60000);
        LCD_init();   
        LCD_clear();
        T1_Init();
       
        drawStaticElements();//把外筐,线条等不改变的东西显示出来
        attachNewBox();//生成一个方块
        disPlayMap();//显示地图(方块可移动的区域)
         ReflashDisPlay();//刷新显示
        GIE;//开全局中断
        while(1)
    {
            test();
    }
}
主函数没什么,只是初始化一下液晶,定时器等。


test()函数:
void test(void)
{
    unsigned char i,j;
        i = getKeyCode();//读取按键
        if(i == UpPress)//右
        {   
            MapXBox++;
                if(GetRightOrLeft(1) == 1)//左右边界判断
                {
                    MapXBox--;//这个是方块图形在地图里的相对位置
                }
        }
        if(i == DownPress)//左
        {
            MapXBox--;
                if(GetRightOrLeft(0) == 1))//左右边界判断
                {
                    MapXBox++;
                }
        }
        if(i == EnterPress)//转
        {
            RotatePosition++;//先假设旋转
                if(RotatePosition == 4)//旋转不能超过4次
                {
                    RotatePosition = 0;
                }
                if((GetBottom() == 1)||(GetRightOrLeft(0) == 1)||(GetRightOrLeft(1) == 1))//旋转之前,先判断边界
                {
                    if(RotatePosition == 0)
                        {
                            RotatePosition = 3;
                        }
                        else
                        {
                        RotatePosition--;
                        }
                }
        }
        GID;//开中断
        disPlayScore();//显示分数,即消的行数
        checkCompleteLine();//判断一行是不是已经填满了
    attachOrEraseBox(1);//在地图区把方块画出来
        disPlayMap();//显示地图到缓存
        ReflashDisPlay();//刷新显示
        attachOrEraseBox(0);//在地图区把方块画擦掉
        GIE;
}

上面这部分思路是这样的:
把生成的方块就直接画在地图上,移动前,擦掉原先的方块图,再画一个新的方块。

出0入0汤圆

发表于 2008-5-8 20:47:14 | 显示全部楼层
等这看你讲解

出0入0汤圆

发表于 2008-5-8 20:48:15 | 显示全部楼层
支持lz
强烈关注

出0入0汤圆

 楼主| 发表于 2008-5-8 21:11:05 | 显示全部楼层
我不是靠做电子行业过活的,工作比较清闲,这个只是业余爱好。的确有接项目,但是没那么多项目接啊,没项目就自己练练语言好了,呵呵,有项目的话给我介绍一下,再说我在这里发的东西也可以让别人看到我是有点能力的嘛,是啵。


把生成的方块就直接画在地图上,移动前,擦掉原先的方块图,再画一个新的方块。每次有输入或者是定时器时间走到,再改变显示的内容。

在中断里面有判断是不是走到底或者底下有已经有方块,到了或有就新生成一个方块,并且把原来的方块放到背景里去。

地图(背景,或者叫可移动范围)是19*16格,本来打算每格一个字节,为了节约RAM,就把每格作为一位来存了,这样数组计算就麻烦了很多,把地图看成19*16格,左顶角算0,0坐标,(0,0)-(0,7)第一个字节,(0,8)到(0,15)第二个字节,(1,0)-(1,7)第3个字节,(1,8)到(1,15)第4个字节,类推,一共38个字节。

函数如下:(我的5110液晶驱动是开了一个显存的,刷新显示就是把显存的数据发到液晶去,下面叫缓存)
void T1_Init(void);//定时器初始化

void drawStaticElements(void);//在缓存上画出边框等不变的东西
unsigned char GetBaiwei(unsigned char temp);//整形取百位的数
unsigned char GetShiwei(unsigned char temp);//十位
unsigned char GetGewei(unsigned char temp);//个位
void disPlayScore(void);//显示分数

void disPlayMap(void);//把地图显示在缓存上
void DrawOrEraseBoxOnMap(unsigned char x,unsigned char y,unsigned char DrawOrErase);//把方块的一个格画在地图上或者擦掉
void attachOrEraseBox(unsigned char DrawOrErase);//整个方块图形画在地图上或者擦掉

unsigned char CheckBitOnMap(unsigned char x,unsigned char y);//检查地图上某格是不是占了
unsigned char CheckBitOnBox(unsigned char x,unsigned char y,unsigned char seclete);//检查方块图形(4*4)的某格是不是1

unsigned char GetBottom(void);//检查底边界
unsigned char GetRightOrLeft(unsigned char where);//检查左右边界

void attachNewBox(void);//新生成一个方块作为被控制对象

void playBoxOnView(void);//在预览位置显示方块

void moveDownOneLine(unsigned char temp);把某行以上图全部下移一格
void checkCompleteLine(void);//判断一行是不是填满了

void test(void);

出0入0汤圆

发表于 2008-5-8 21:14:33 | 显示全部楼层
强烈关注中……

出0入0汤圆

 楼主| 发表于 2008-5-8 21:15:32 | 显示全部楼层
程序贴出来

这个是boxgame.c:

#include"../5110LCD/5110LCD.h"
#include"../TABLES/bmp.h"
#include"../TABLES/english_6x8.h"
#include"../KEYSCAN/keyscan.h"
#include"../DELAY/delayh.h"
#include<iom16v.h>
#include<MACROS.h>
#include"boxgame.h"

/****************************全局变量**********************************/
unsigned char mapArray[MapLength][2] = //总地图
{
0xff,0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,
0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0xff,0xff
};

unsigned char allScore = 0;//总分即所消的行数
unsigned char MapXBox = 7;//此刻图形的X坐标
unsigned char MapYBox = 0;//此刻图形的Y坐标
unsigned char MapNumBox = 0;//此刻加载上来的图形名
unsigned char MapNumBoxNext = 0;//下一个的图形名
unsigned char RotatePosition = 0;//旋转的位置
unsigned char times = 0;//计数
unsigned char TimeLevel = 5;//定时器溢出次数,可以作为难度级别

/****************************code量**********************************/
const unsigned char table2[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
const unsigned char boxesArray[7][4][4]=//七种图形,四种方向,[图形][方向][点阵]
{
/*
  □□□□     □□□□     □□□□     □□□□      
  □■□□     □□□□     □■■□     □□□□      
  □■□□     □□■□     □□■□     ■■■□      
  □■■□     ■■■□     □□■□     ■□□?
*/
    0x00,0x0e,0x08,0x00,
        0x08,0x08,0x0c,0x00,
        0x00,0x02,0x0e,0x00,
        0x0c,0x04,0x04,0x00,
       
/*
  □□□□     □□□□     □□□□     □□□□      
  □■■□     ■■■□     □□■□     ■□□□      
  □■□□     □□■□     □□■□     ■■■□      
  □■□□     □□□□     □■■□     □□□□
*/
    0x00,0x0e,0x02,0x00,
        0x06,0x04,0x04,0x00,
        0x00,0x08,0x0e,0x00,
        0x02,0x02,0x06,0x00,
       
/*
  □□□□     □□□□     □□□□     □□□□
  □□□□     □■□□     □□□□     ■□□□
  □■□□     ■■□□     ■■■□     ■■□□
  ■■■□     □■□□     □■□□     ■□□□
*/
    0x08,0x0c,0x08,0x00,
        0x04,0x0e,0x00,0x00,
        0x04,0x0c,0x04,0x00,
        0x0e,0x04,0x00,0x00,
       
/*
  □□□□     □□□□     □□□□     □□□□
  □□□□     ■□□□     □□□□     ■□□□
  □■■□     ■■□□     □■■□     ■■□□
  ■■□□     □■□□     ■■□□     □■□□
*/
    0x08,0x0c,0x04,0x00,
        0x06,0x0c,0x00,0x00,
        0x08,0x0c,0x04,0x00,
        0x06,0x0c,0x00,0x00,
  
/*
  □□□□     □□□□     □□□□     □□□□
  □□□□     □■□□     □□□□     □■□□
  ■■□□     ■■□□     ■■□□     ■■□□
  □■■□     ■□□□     □■■□     ■□□□
*/
    0x04,0x0c,0x08,0x00,
        0x0c,0x06,0x00,0x00,
        0x04,0x0c,0x08,0x00,
        0x0c,0x06,0x00,0x00,

/*
  □■□□     □□□□     □□■□     □□□□
  □■□□     □□□□     □□■□     ■■■■
  □■□□     ■■■■     □□■□     □□□□
  □■□□     □□□□     □□■□     □□□□
*/
    0x00,0x0f,0x00,0x00,
        0x04,0x04,0x04,0x04,
        0x00,0x00,0x0f,0x00,
        0x02,0x02,0x02,0x02,

/*
  □□□□     □□□□     □□□□     □□□□
  □□□□     □□□□     □□□□     □□□□
  □■■□     □■■□     □■■□     □■■□
  □■■□     □■■□     □■■□     □■■□
*/
    0x00,0x0c,0x0c,0x00,
    0x00,0x0c,0x0c,0x00,
    0x00,0x0c,0x0c,0x00,
    0x00,0x0c,0x0c,0x00,
};
/**************************控制函数************************************/
void T1_Init(void)//初始化定时器
{
        TCCR1A &= ~(1 << WGM10);
        TCCR1A &= ~(1 << WGM11);
        TCCR1B &= ~(1 << WGM12);
        TCCR1B &= ~(1 << WGM13);
        TCCR1B |= (1 << CS10);
        TCCR1B &= ~(1 << CS11);
        TCCR1B &= ~(1 << CS12);
        TIMSK |= (1 << TOIE1);
}

void drawStaticElements(void)//显示静态元素,即筐架
{
    DrawRectangleLine(57,0,83,47,1);//右筐
    DrawGraphics(font6x8[46],6,8,58,2);//N
    DrawGraphics(font6x8[37],6,8,64,2);//E
        DrawGraphics(font6x8[56],6,8,70,2);//X
        DrawGraphics(font6x8[52],6,8,76,2);//T
        DrawLine(58,26,82,26);//下线
    DrawLine(58,27,82,27);//下线
        DrawGraphics(font6x8[44],6,8,58,29);//l
    DrawGraphics(font6x8[41],6,8,64,29);//i
        DrawGraphics(font6x8[46],6,8,70,29);//n
        DrawGraphics(font6x8[37],6,8,76,29);//e
    DrawLine(60,45,80,45);//下线       
}
unsigned char GetBaiwei(unsigned char temp)//从整数中取百位数
{
        temp = temp/100;
        return temp;
}
unsigned char GetShiwei(unsigned char temp)//从整数中取十位数
{
        if(temp > 99)
        {
                temp = temp - GetBaiwei(temp)*100;
        }
        temp = temp/10;
        return temp;
}
unsigned char GetGewei(unsigned char temp)//从整数中取个位数
{
        temp = temp%10;
        return temp;
}
void disPlayScore(void)//把分数显示出来
{
    ClearArea(61,36,19,9);
    if(allScore <= 0xff)
        {
        DrawGraphics(font6x8[16+GetBaiwei(allScore)],6,8,61,37);
        DrawGraphics(font6x8[16+GetShiwei(allScore)],6,8,67,37);
            DrawGraphics(font6x8[16+GetGewei(allScore)],6,8,73,37);
        }
}
void disPlayMap(void)//把地图显示出来
{
    unsigned char i,j,temp1,temp2,temp3;//temp1判断是上字节还是下字节,temp2把0-15转换成两个0-7,temp3左移的中间变量

        for(i=0;i<MapLength;i++)
    {       
            for(j=0;j<MapWeight;j++)//16-1
            {
                    if(j>7)//8-15
                    {
                         temp1 = 1;
                            temp2 = j - 8;//0-7
                    }
                    else//0-7
                    {
                        temp1 = 0;
                            temp2 = j;//0-7
                    }
                        temp3 = mapArray[temp1] << (7 - temp2);
                        temp3 = temp3 >> 7;
                    if(temp3 == 1)//如果有1就画方块
                        {
                                DrawGraphics(box1,3,3,i*3,j*3);
                        }
                        else//如果没1就擦掉
                        {
                            ClearArea(i*3,j*3,3,3);
                        }
                }
        }
}
void DrawOrEraseBoxOnMap(unsigned char x,unsigned char y,unsigned char DrawOrErase)
//从0开始,DrawOrErase当是0的时候擦除,是1的时候写入
{
    unsigned char temp,temp1;
        if((y + 1) % 8 == 0)
        {
            temp = (y + 1) / 8;
        }
        else
        {
            temp = ((y + 1) / 8) + 1;
        }
        temp1 = y % 8;
        if(DrawOrErase == 1)
        {
            mapArray[x][temp - 1] |= table2[temp1];
        }
        else
        {
            mapArray[x][temp - 1] &= ~table2[temp1];
        }
}

void attachOrEraseBox(unsigned char DrawOrErase)
{
        unsigned char i,j;
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
                {
                        if(CheckBitOnBox(i,j,MapNumBox))
                        {
                                DrawOrEraseBoxOnMap(i+MapXBox,MapYBox+j,DrawOrErase);
                        }
                }
        }
}

unsigned char CheckBitOnMap(unsigned char x,unsigned char y)
{
    unsigned char temp,temp1;
        if((y + 1) % 8 == 0)
        {
            temp = (y + 1) / 8;
        }
        else
        {
            temp = ((y + 1) / 8) + 1;
        }
        temp1 = y % 8;
        return (mapArray[x][temp - 1] & table2[temp1]);
}

unsigned char CheckBitOnBox(unsigned char x,unsigned char y,unsigned char seclete)
{
        return (boxesArray[seclete][RotatePosition][x] & table2[y]);
}

unsigned char GetBottom(void)//底部触碰检查
{
    unsigned char i,x,y,temp1,temp2;
        for(y=0;y<4;y++)
        {
            i = 3 - y;
            for(x=0;x<4;x++)
                {
                    temp1 = CheckBitOnMap(MapXBox+x,MapYBox+i);
                        temp2 = CheckBitOnBox(x,i,MapNumBox);
                        if(temp1&&temp2)
                        {
                            return 1;//有冲突
                        }
                }
        }
    return 0;//没冲突
}

unsigned char GetRightOrLeft(unsigned char where)//左右触碰检查,where=0:左,where=1:右
{
    unsigned char i,x,y,temp1,temp2;
        for(x=0;x<4;x++)
        {
            if(where)
                {
                i = 3 - x;
                }
                else
                {
                    i = x;
                }
            for(y=0;y<4;y++)
                {
            temp1 = CheckBitOnMap(MapXBox+i,MapYBox+y);
                        temp2 = CheckBitOnBox(i,y,MapNumBox);
                        if(temp1&&temp2)
                        {
                            return 1;//有冲突
                        }
                }
        }
    return 0;
}

void attachNewBox(void)
{
    attachOrEraseBox(1);
       
    MapNumBox = MapNumBoxNext;
        MapNumBoxNext ++;
        if(MapNumBoxNext == 7)
        {
            MapNumBoxNext = 0;
        }
       
        playBoxOnView();//显示预览
        MapXBox = 7;
        MapYBox = 0;
        RotatePosition = 0;
}

void playBoxOnView(void)
{
    unsigned char i,j;
        ClearArea(65,12,12,12);
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
                {
                        if(CheckBitOnBox(i,j,MapNumBoxNext))
                    {
                            DrawGraphics(box1,3,3,(i*3+65),(j*3+12));
                    }
                }
        }
}

void moveDownOneLine(unsigned char temp)//输入的是把从哪行开始,在map上所有该行以上的行下落一行
{
    unsigned char x,y,temp2,temp3,i;
    if(temp < 8)
        {
            x = temp;
                y = 0;
        }
        if(temp >7)
        {
            x = temp - 8;
                y = 1;
        }
        for(i=1;i<(MapLength-1);i++)//左右边界不移
        {
            if(y == 1)
                {
                    mapArray[0] = mapArray[0] << 1;
                }
            temp2 = mapArray[y] >> (x + 1);//先把指定行下面的保存下来
                temp2 = temp2 << (x + 1);
                temp3 = mapArray[y] << (8 - x);//把指定行上面的下移一个,不过要先把原来下面的数据清掉
                temp3 = temp3 >> (7 - x);
                mapArray[y] = temp2 | temp3;//把两个数叠加起来
        }
}

void checkCompleteLine(void)
{
    unsigned char x1,y1;
        unsigned char num = 0;
        for(y1=0;y1<(MapWeight-1);y1++)
        {
            num = 0;
            for(x1=1;x1<(MapLength-1);x1++)
                {
                    if(CheckBitOnMap(x1,y1) == 0)
                        {
                                num = 1;
                        }
                }
                if(num == 0)
                {
                    moveDownOneLine(y1);
                        allScore++;
                }
        }
}

void test(void)
{
    unsigned char i,j;
        i = getKeyCode();
        if(i == UpPress)//右
        {   
            MapXBox++;
                if(GetRightOrLeft(1) == 1)
                {
                    MapXBox--;
                }
        }
        if(i == DownPress)//左
        {
            MapXBox--;
                if(GetRightOrLeft(0) == 1)
                {
                    MapXBox++;
                }
        }
        if(i == EnterPress)//转
        {
            RotatePosition++;
                if(RotatePosition == 4)
                {
                    RotatePosition = 0;
                }
                if((GetBottom() == 1)||(GetRightOrLeft(0) == 1)||(GetRightOrLeft(1) == 1))
                {
                    if(RotatePosition == 0)
                        {
                            RotatePosition = 3;
                        }
                        else
                        {
                        RotatePosition--;
                        }
                }
        }
        GID;
        disPlayScore();
        checkCompleteLine();
    attachOrEraseBox(1);
        disPlayMap();
        ReflashDisPlay();
        attachOrEraseBox(0);
        GIE;
}

#pragma interrupt_handler Int_TIMER1_OVF: iv_TIMER1_OVF  //???/???1 ????
void Int_TIMER1_OVF(void)
{
    unsigned char temp;
    times++;
        if(times == TimeLevel)
        {
            MapYBox++;
        if(GetBottom() == 1)//碰撞
                {
                    MapYBox--;
                        attachNewBox();
                }
                attachOrEraseBox(1);
            disPlayMap();
            ReflashDisPlay();
            attachOrEraseBox(0);
                times = 0;
        }
}

出0入0汤圆

 楼主| 发表于 2008-5-8 21:18:47 | 显示全部楼层
下面是这个的头boxgame.h

#ifndef __BOXGAME__
#define __BOXGAME__

/*****************************************************************************/
/*本文件需要的外部函数有                                                     */
/*    5110LCD.h:                                                            */
/*            DrawRectangleLine画方框                                        */
/*                          DrawLine画直线                                                 */
/*                          DrawGraphics画图形                                             */
/*                          DrawArea画黑方块                                               */
/*                          ClearArea画白方块                                              */
/*                                                                                         */
/*****************************************************************************/
#define MapLength 19 //地图宽
#define MapWeight 16 //地图高

#define GIE                                 (SREG |= BIT(7))
#define GID                                   (SREG &= ~BIT(7))

void T1_Init(void);

void drawStaticElements(void);
unsigned char GetBaiwei(unsigned char temp);
unsigned char GetShiwei(unsigned char temp);
unsigned char GetGewei(unsigned char temp);
void disPlayScore(void);

void disPlayMap(void);
void DrawOrEraseBoxOnMap(unsigned char x,unsigned char y,unsigned char DrawOrErase);
void attachOrEraseBox(unsigned char DrawOrErase);

unsigned char CheckBitOnMap(unsigned char x,unsigned char y);
unsigned char CheckBitOnBox(unsigned char x,unsigned char y,unsigned char seclete);

unsigned char GetBottom(void);
unsigned char GetRightOrLeft(unsigned char where);

void attachNewBox(void);

void playBoxOnView(void);

void moveDownOneLine(unsigned char temp);
void checkCompleteLine(void);

void test(void);

#endif

出0入0汤圆

发表于 2008-5-8 21:20:04 | 显示全部楼层
站长哪儿去了,楼主太需要一条裤子了!

出0入0汤圆

 楼主| 发表于 2008-5-8 21:24:07 | 显示全部楼层
我用的是m16L,5110液晶部分占了11%左右空间,游戏部分占了17%空间,好象还凑合

有不懂的提问

出0入0汤圆

 楼主| 发表于 2008-5-8 21:26:18 | 显示全部楼层
呵呵,电子猫,给我介绍项目做啊!我太清闲了

出0入0汤圆

 楼主| 发表于 2008-5-8 21:26:47 | 显示全部楼层
下面我把函数逐个逐个解释一下,这个工程量就大了

出0入0汤圆

发表于 2008-5-8 21:32:23 | 显示全部楼层
过来关注    mark

出0入0汤圆

 楼主| 发表于 2008-5-8 21:33:25 | 显示全部楼层
我用的是ICCAVR

void T1_Init(void);定时器初始化,用的是普通模式溢出中断,不知道怎么配置的后面就不用看了。

#pragma interrupt_handler Int_TIMER1_OVF: iv_TIMER1_OVF  
void Int_TIMER1_OVF(void)
{
    unsigned char temp;
    times++;
        if(times == TimeLevel)
        {
            MapYBox++;
        if(GetBottom() == 1)//碰撞
                {
                    MapYBox--;
                        attachNewBox();
                }
                attachOrEraseBox(1);
            disPlayMap();
            ReflashDisPlay();
            attachOrEraseBox(0);
                times = 0;
        }
}
这个是定时器1溢出中断,溢出次数到了上面的TimeLevel时,方块就下移一次,确定可以下移之前,,先假设能下移,把MapYBox++,然后开始边界判断,如果MapYBox增加以后,下边界检测到方块区域的格是1,同时地图的这个格也是1,说明重叠了,MapYBox增加失败,再还原MapYBox,即MapYBox--,同时生成一个新的可被操作的方块,把走到位的这个方块放到地图的数组相应位置去。再刷新显示。

出0入0汤圆

 楼主| 发表于 2008-5-8 21:40:30 | 显示全部楼层
void drawStaticElements(void);

这个不用怎么说明,就是单纯的在液晶上把外框,还有文字等不变化的图画出来,一共只画一次。

unsigned char GetBaiwei(unsigned char temp);
unsigned char GetShiwei(unsigned char temp);
unsigned char GetGewei(unsigned char temp);
这三个函数是从一个整形数中取得百位、十位、个位的数值,并返回,没啥好说的

void disPlayScore(void)//把分数显示出来
{
    ClearArea(61,36,19,9);//先清空这片区域
    if(allScore <= 0xff)
        {
        DrawGraphics(font6x8[16+GetBaiwei(allScore)],6,8,61,37);
        DrawGraphics(font6x8[16+GetShiwei(allScore)],6,8,67,37);
            DrawGraphics(font6x8[16+GetGewei(allScore)],6,8,73,37);
        }
}
这个函数是在屏幕右下位置显示出分数,即消的行数,在写之前要把这片地方擦成白的,不然写过的数字会重叠,用到上面3个函数,font6x8[16+GetBaiwei(allScore)],是在英文点阵表里找到相应数字的查表,用的次数不多就没做成一个函数。allScore是总分数,因为是整形,就不能超过255。

出0入0汤圆

发表于 2008-5-8 21:41:15 | 显示全部楼层
谢谢楼主!
学习......

出0入0汤圆

 楼主| 发表于 2008-5-8 21:50:31 | 显示全部楼层
void disPlayMap(void)//把地图显示出来
{
    unsigned char i,j,temp1,temp2,temp3;//temp1判断是上字节还是下字节,temp2把0-15转换成两个0-7,temp3左移的中间变量

        for(i=0;i<MapLength;i++)
    {       
            for(j=0;j<MapWeight;j++)//16-1
            {
                    if(j>7)//8-15
                    {
                         temp1 = 1;
                            temp2 = j - 8;//0-7
                    }
                    else//0-7
                    {
                        temp1 = 0;
                            temp2 = j;//0-7
                    }
                        temp3 = mapArray[temp1] << (7 - temp2);
                        temp3 = temp3 >> 7;
                    if(temp3 == 1)//如果有1就画方块
                        {
                                DrawGraphics(box1,3,3,i*3,j*3);
                        }
                        else//如果没1就擦掉
                        {
                            ClearArea(i*3,j*3,3,3);
                        }
                }
        }
}

这个是把地图显示在缓存上,上面说了这个存放地图的数组结构,关于如何编历数组这里就不说了。函数中可以看到如果是0就擦除,如果是1就画方块,是因为如果不擦掉,有可能会在刷新显示时,把以前的地图画在现在的空白地方。上面判断0-7啊这些是因为纵向16格是数组中紧靠的两个元素,那么第8到16格就是第二个元素,在数组中就等于是第二个元素的第0位到第7位。左右移是舍弃这个字节其他的位,这样比较方便。

出0入0汤圆

发表于 2008-5-8 21:55:30 | 显示全部楼层
顶~~!
好东西大家分享!
强烈支持~!!

出0入0汤圆

 楼主| 发表于 2008-5-8 22:00:21 | 显示全部楼层
void DrawOrEraseBoxOnMap(unsigned char x,unsigned char y,unsigned char DrawOrErase)
//从0开始,DrawOrErase当是0的时候擦除,是1的时候写入
{
    unsigned char temp,temp1;
        if((y + 1) % 8 == 0)
        {
            temp = (y + 1) / 8;
        }
        else
        {
            temp = ((y + 1) / 8) + 1;
        }
        temp1 = y % 8;
        if(DrawOrErase == 1)
        {
            mapArray[x][temp - 1] |= table2[temp1];
        }
        else
        {
            mapArray[x][temp - 1] &= ~table2[temp1];
        }
}
下面的函数是在把整个方块画到地图上,上面是把方块的一个点画到地图上,这样功能分开,容易搞清楚
void attachOrEraseBox(unsigned char DrawOrErase)
{
        unsigned char i,j;
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
                {
                        if(CheckBitOnBox(i,j,MapNumBox))
                        {
                                DrawOrEraseBoxOnMap(i+MapXBox,MapYBox+j,DrawOrErase);
                        }
                }
        }
}

这个其实是把存方块的数组里的元素的位取出来,放到地图上相应元素的相应位上去,一切为了节约嘛,我存方块的数组也是用位来做方块的外型的。

参数xy是把方块放在离地图左顶点的相对距离。
((y + 1) % 8 == 0 :地图坐标是从0开始到(MapWeight-1),MapWeight是地图高度,不能从0开始数,要从1开始数,y从0开始,如果y是7,实际上是第8格,y+1以后就对上了,这样前面8格是一个数组元素,后面8格是数组元素。

为什么要加个功能,擦除呢,是因为方块是直接画在地图上的,即每次的方块移动,都是先把这个方块数组里的数放到地图数组的相应位置上,那么要移动方块,就必须先把移动前的方块图形从地图数组中删去。

出0入0汤圆

发表于 2008-5-8 22:06:29 | 显示全部楼层
这帖不顶不行

出0入0汤圆

 楼主| 发表于 2008-5-8 22:19:10 | 显示全部楼层
unsigned char CheckBitOnMap(unsigned char x,unsigned char y)
{
    unsigned char temp,temp1;
        if((y + 1) % 8 == 0)
        {
            temp = (y + 1) / 8;
        }
        else
        {
            temp = ((y + 1) / 8) + 1;
        }
        temp1 = y % 8;
        return (mapArray[x][temp - 1] & table2[temp1]);
}

unsigned char CheckBitOnBox(unsigned char x,unsigned char y,unsigned char seclete)
{
        return (boxesArray[seclete][RotatePosition][x] & table2[y]);
}

这两个函数分别是检查地图上某格是不是已经有东西了(即在地图数组中找到相应的位,看它是不是“1”,是1代表有东西),和检查4*4的方块某格是不是有图。
CheckBitOnBox的一个参数seclete,seclete是代表方块名,用这个参数是因为新生成一个方块到地图上要用这个函数,同时生成之前的方块也要用这个函数。
RotatePosition是旋转以后的方块名:
这样一个数组:/*
  □□□□     □□□□     □□□□     □□□□        
  □■■□     ■■■□     □□■□     ■□□□        
  □■□□     □□■□     □□■□     ■■■□        
  □■□□     □□□□     □■■□     □□□□
*/
    0x00,0x0e,0x02,0x00,
        0x06,0x04,0x04,0x00,
        0x00,0x08,0x0e,0x00,
        0x02,0x02,0x06,0x00,
的四行元素,每行存了一个旋转位置,一个字节存的是纵向看一列




这样一列的数是0x0e,是因为我们已经假设了前面还有四个空格(纵想取模,高位在上)











检查一个字节的某位是0还是1的公式就是(x & y),这个表达试结果是1,那么说明x的第y位是1。但y不是0-7,而是0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80。

出0入0汤圆

发表于 2008-5-8 22:19:28 | 显示全部楼层
学习!关注

出0入0汤圆

发表于 2008-5-8 22:24:41 | 显示全部楼层
好东西!!
学习!

出0入0汤圆

 楼主| 发表于 2008-5-8 22:38:49 | 显示全部楼层
unsigned char GetBottom(void)//底部触碰检查
{
    unsigned char i,x,y,temp1,temp2;
        for(y=0;y<4;y++)
        {
            i = 3 - y;
            for(x=0;x<4;x++)
                {
                    temp1 = CheckBitOnMap(MapXBox+x,MapYBox+i);
                        temp2 = CheckBitOnBox(x,i,MapNumBox);
                        if(temp1&&temp2)
                        {
                            return 1;//有冲突
                        }
                }
        }
    return 0;//没冲突
}

unsigned char GetRightOrLeft(unsigned char where)//左右触碰检查,where=0:左,where=1:右
{
    unsigned char i,x,y,temp1,temp2;
        for(x=0;x<4;x++)
        {
            if(where)
                {
                i = 3 - x;
                }
                else
                {
                    i = x;
                }
            for(y=0;y<4;y++)
                {
            temp1 = CheckBitOnMap(MapXBox+i,MapYBox+y);
                        temp2 = CheckBitOnBox(i,y,MapNumBox);
                        if(temp1&&temp2)
                        {
                            return 1;//有冲突
                        }
                }
        }
    return 0;
}

两个边界判断,方块每走一格,都先假设能走,再去看看方块所走的位置地图上是不是有东西,有就重叠了,那么假设不成立,那么方块再退回去,因为这个过程当中没有刷新显示,所以方块走下去再退回来这个过程看不到。
temp1 = CheckBitOnMap(MapXBox+x,MapYBox+i);
temp2 = CheckBitOnBox(x,i,MapNumBox);
if(temp1&&temp2)
{
    return 1;//有冲突
}
temp1是检查某个位置在地图上是不是1,
temp2是检查该位置有没有方块
如果两个同时为1,说明有重叠。

出0入0汤圆

 楼主| 发表于 2008-5-8 22:44:16 | 显示全部楼层
void attachNewBox(void)
{
    attachOrEraseBox(1);
       
    MapNumBox = MapNumBoxNext;
        MapNumBoxNext ++;
        if(MapNumBoxNext == 7)
        {
            MapNumBoxNext = 0;
        }
       
        playBoxOnView();//显示预览
        MapXBox = 7;
        MapYBox = 0;
        RotatePosition = 0;
}

这个是生成新的方块,首先attachOrEraseBox(1),就是把旧的方块写到数组里去,作为背景存在。
MapNumBox = MapNumBoxNext;//现在可以操作的图形名是上一次预览时的图形
MapNumBoxNext ++;//预览的新图形
if(MapNumBoxNext == 7)//不能超过7个,因为只有7种图形
{
    MapNumBoxNext = 0;
}
这里可以用随机数去调一个新方块的名字,但是伪随机数没啥意思,干脆直接下一个图形好了。
MapXBox = 7;
MapYBox = 0;
RotatePosition = 0;
这三个是新生成的方块图出现时的相对地图左上角顶点的坐标,和旋转的方向,这些都可以用随机数去取。

出0入0汤圆

 楼主| 发表于 2008-5-8 22:47:10 | 显示全部楼层
void playBoxOnView(void)
{
    unsigned char i,j;
        ClearArea(65,12,12,12);
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
            {
                if(CheckBitOnBox(i,j,MapNumBoxNext))
                     {
                    DrawGraphics(box1,3,3,(i*3+65),(j*3+12));
                    }
            }
        }
}

显示预览,这个没什么好说,就是在预览的位置按方块数组的内容画box1数组里的图,box1数组就是楼主位图上的一个空心的方格。

出0入0汤圆

 楼主| 发表于 2008-5-8 22:54:46 | 显示全部楼层
void moveDownOneLine(unsigned char temp)//输入的是把从哪行开始,在map上所有该行以上的行下落一行
{
    unsigned char x,y,temp2,temp3,i;
    if(temp < 8)//如果列数超过8,那么就是第二个字节
        {
            x = temp;
                y = 0;
        }
        if(temp >7)//没超过就是第一个字节
        {
            x = temp - 8;
                y = 1;
        }
        for(i=1;i<(MapLength-1);i++)//左右边界不移
        {
            if(y == 1)
                {
                    mapArray[0] = mapArray[0] << 1;
                }
            temp2 = mapArray[y] >> (x + 1);//先把指定行下面的保存下来
                temp2 = temp2 << (x + 1);
                temp3 = mapArray[y] << (8 - x);//把指定行上面的下移一个,不过要先把原来下面的数据清掉
                temp3 = temp3 >> (7 - x);
                mapArray[y] = temp2 | temp3;//把两个数叠加起来
        }
}

这个的输入是要删除的行,删除的过程是把该行以上所有内容下移。
现在假设是这样的:
■□0
■□1
■□2
■□3
■□4
■□5
■□6
■□7
■□8
■□9
■□10
■□11
■□12
■□13
■□14
■□15
一纵列中,0-7是数组中一个字节,8-15是另一个字节,现在要删除第9行,那么先把上面一个字节下移(数组操作是左移),再把第二个字节的第2位删掉,把第一位移到第二位的地方,把第0位移到第一位的地方,把上一个字节的最后一位放到本字节的第0位来。

void checkCompleteLine(void)
{
    unsigned char x1,y1;
        unsigned char num = 0;
        for(y1=0;y1<(MapWeight-1);y1++)
        {
            num = 0;
            for(x1=1;x1<(MapLength-1);x1++)
                {
                    if(CheckBitOnMap(x1,y1) == 0)
                        {
                                num = 1;
                        }
                }
                if(num == 0)
                {
                    moveDownOneLine(y1);
                        allScore++;
                }
        }
}
判断某行是不是已经填满了,我想通过上面那么多楼的讲解应该知道怎么去遍历这个数组了

出0入0汤圆

 楼主| 发表于 2008-5-8 22:58:21 | 显示全部楼层
好了,所有的函数都说了一遍,其实游戏思路很简单,就是
1。用一个2维数组做地图,地图就是方块所能走的地方,所有操作都是针对这个数组
2。假设移动了
3。判断能不能移
4。能就移好了,不能就退回去,再把方块变成背景,再生成一个新方块
5。每动一次看看有没有可以消除的行,有就消除,没有就算了
就这样

有不知道的地方可以问问

出0入0汤圆

发表于 2008-5-8 23:21:31 | 显示全部楼层
写的好详细阿,赞一个~

出0入0汤圆

 楼主| 发表于 2008-5-8 23:27:35 | 显示全部楼层
波仔是我崇拜的对象之一,很开心
呵呵。波仔一看相貌就知道是个写程序很牛的高手啊。

出0入0汤圆

发表于 2008-5-8 23:47:17 | 显示全部楼层
楼主,我确实有个小项目,AT128做主控芯片,带一个320x240的液晶屏,触摸功能可选做。外围只有几个数字电位器等纯数字芯片及开关量控制,无需处理任何的模拟信号。开发的重点在人性化的菜单设计、多国语言、通过导航键输入英文字母、微打的控制(可选做)等。的如果你有兴趣,可以发邮件联系。我的邮箱是ecat08@hotmail.com

出0入0汤圆

 楼主| 发表于 2008-5-9 00:06:07 | 显示全部楼层
天哪,这个项目要被程序给绕死……你没有QQ吗?
邮件发了

出0入0汤圆

发表于 2008-5-9 00:11:14 | 显示全部楼层
QQ有的。今天不聊了,太晚了。

出0入0汤圆

发表于 2008-5-9 08:51:20 | 显示全部楼层
不顶对不起楼主,呵呵

出0入0汤圆

发表于 2008-5-9 08:56:12 | 显示全部楼层
江西九江,很亲切呀.顶

出0入0汤圆

发表于 2008-5-9 09:21:48 | 显示全部楼层
这个要顶。。。

出0入0汤圆

发表于 2008-5-9 09:27:37 | 显示全部楼层
to 【35楼】 shrlyq 胖胖心碎了
    呵呵,很荣幸...
我写程序也不是太行,往往都是先把功能搞出来,最后加注释。 这样写出来的结构可能不是太好。 最近的工作都是在移植厂商给的代码,有组织写的代码还是不多的(不过很冗余)。

出0入0汤圆

发表于 2008-5-9 09:39:05 | 显示全部楼层
太牛了

出0入0汤圆

发表于 2008-5-9 09:52:49 | 显示全部楼层
顶,开源的最高境界

出0入10汤圆

发表于 2008-5-9 09:53:10 | 显示全部楼层
不错, 我手头有彩屏的,也要搞一个

出0入10汤圆

发表于 2008-5-9 09:59:50 | 显示全部楼层
要求加裤

出0入0汤圆

发表于 2008-5-9 12:12:36 | 显示全部楼层
向楼主学习!

出0入0汤圆

发表于 2008-5-9 12:49:08 | 显示全部楼层
不得了,又一个牛人

出0入0汤圆

发表于 2008-5-9 12:49:54 | 显示全部楼层
楼主不错,夸一个!!!

出0入0汤圆

发表于 2008-5-9 12:57:59 | 显示全部楼层
我来啦,顶一下.

出0入0汤圆

发表于 2008-5-9 13:59:33 | 显示全部楼层
又见大师,还是个好人

出0入0汤圆

发表于 2008-5-9 16:40:03 | 显示全部楼层
这个我要顶!

出0入147汤圆

发表于 2008-5-9 16:58:32 | 显示全部楼层
标记一下,认真学习

出0入0汤圆

 楼主| 发表于 2008-5-9 18:12:50 | 显示全部楼层
呵呵,我只是一个懂点技术的穷人。

出0入0汤圆

发表于 2008-5-9 18:36:48 | 显示全部楼层
顶了   我也想做一个  不过不想吵你的  就没详细看  哈哈

出0入0汤圆

发表于 2008-5-9 21:37:23 | 显示全部楼层
顶一下.

出0入0汤圆

 楼主| 发表于 2008-5-9 22:15:18 | 显示全部楼层
谢谢捧场啊!!

出0入0汤圆

发表于 2008-5-9 23:41:08 | 显示全部楼层
不错,支持
羡慕楼主的工作,有那么多时间清闲...

出0入0汤圆

发表于 2008-5-10 05:41:06 | 显示全部楼层
楼主有电路图吗?

出0入0汤圆

发表于 2008-5-10 07:31:50 | 显示全部楼层
确实有水平.与你们比,我还是不作技术了.

出0入0汤圆

发表于 2008-5-10 08:33:18 | 显示全部楼层
出來頂一個走人~

出0入0汤圆

发表于 2008-5-10 08:35:41 | 显示全部楼层
不顶对不起自己!

出0入0汤圆

发表于 2008-5-10 08:50:24 | 显示全部楼层
不顶对不起我自己

出0入0汤圆

发表于 2008-5-10 11:37:33 | 显示全部楼层
什么时候我才能像楼主一样做一个出来呢?书上例子都看不懂,好伤心啊

出0入0汤圆

发表于 2008-5-10 18:53:46 | 显示全部楼层
绝对是好东西!!

出0入0汤圆

发表于 2008-5-10 21:39:17 | 显示全部楼层
【5楼】 ecat 电子猫
积分:1356
派别:
等级:------
来自:
        楼主多接项目,也不会成为头像上那么惨的样子了啦,哈哈!  
////////////////////////////////////////////////////////////////////////////////
      别人是帮主啊!   比我们技术人员强多了

出0入0汤圆

 楼主| 发表于 2008-5-11 23:44:17 | 显示全部楼层
电路图啊,很简单的,就是把5110液晶接上,只要有了1。在任意位置画任意面积图形的函数,2。任意面积填充0的函数,3。画直线的函数就可以了,还有3个直连的按键,好象没必要有硬件图啊。

出0入0汤圆

发表于 2008-5-12 00:41:59 | 显示全部楼层
ding a  顶

出0入0汤圆

发表于 2008-5-12 10:02:39 | 显示全部楼层
本来以为用VC++做出俄罗斯方块的人很牛的,现在出了个更牛的!佩服,学习这种精神!

出0入0汤圆

发表于 2008-5-13 10:49:07 | 显示全部楼层
再搬楼主顶一次

出0入0汤圆

发表于 2008-5-13 14:19:24 | 显示全部楼层
好贴,北交大离奥运100天的时候弄了一个在整个宿舍楼窗户上亮出一个京印的活动,我想要是把这宿舍的灯都接上控制,变成俄罗斯方块的屏幕,那玩起来不是很爽^_^,100块钱玩5分钟,哈哈

出0入0汤圆

发表于 2008-5-17 00:49:02 | 显示全部楼层
【71楼】 yycool
北理工的想出用宿舍灯来道别,你们想用宿舍灯来玩俄罗斯方块!!!!
也得看看宿舍的哥们同意么!

出0入0汤圆

发表于 2008-5-17 16:41:34 | 显示全部楼层

出0入4汤圆

发表于 2008-5-18 13:14:10 | 显示全部楼层

出0入0汤圆

发表于 2008-8-16 14:54:52 | 显示全部楼层
好厉害。楼主可否把原理图也传上来看看。

出0入0汤圆

发表于 2008-8-16 15:52:30 | 显示全部楼层
不错......

出0入0汤圆

发表于 2008-8-16 17:17:00 | 显示全部楼层

出0入0汤圆

发表于 2008-8-16 18:37:10 | 显示全部楼层

出0入4汤圆

发表于 2008-8-16 18:45:17 | 显示全部楼层
记号

出0入0汤圆

发表于 2008-8-16 19:16:10 | 显示全部楼层
楼主精神可佳呀!顶一个!

出0入0汤圆

发表于 2008-8-16 19:27:14 | 显示全部楼层
真不赖!

出0入0汤圆

发表于 2008-8-16 21:14:44 | 显示全部楼层
呵.游戏与学习结合. 是时候买个5510玩玩

出0入0汤圆

发表于 2008-8-16 22:43:29 | 显示全部楼层
又一牛人

出0入0汤圆

发表于 2008-8-16 23:20:56 | 显示全部楼层
楼主有点像天龙八部里的扫地僧;
呵呵,佩服;

出0入0汤圆

发表于 2008-8-17 14:27:14 | 显示全部楼层
不错不错!!!

出0入0汤圆

发表于 2008-8-17 16:10:52 | 显示全部楼层
牛,图像更牛

出0入0汤圆

发表于 2008-8-17 19:51:20 | 显示全部楼层
我喜欢!!!!

出0入0汤圆

发表于 2008-8-18 08:42:15 | 显示全部楼层
3Q,学习了.

出0入0汤圆

发表于 2008-8-18 10:15:17 | 显示全部楼层
呵呵   江西九江   好象电子行业发展的不太好的
能有LZ这样的人    很不得了了
我也是九江人  LZ能不能给个联系方式  以后多联系

出0入0汤圆

发表于 2008-8-18 11:41:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-8-18 12:26:48 | 显示全部楼层
LZ是九江人,老乡啊

出0入0汤圆

发表于 2008-8-20 22:29:25 | 显示全部楼层
牛人

出0入0汤圆

发表于 2008-8-22 21:19:01 | 显示全部楼层
感想感做,值得我好好学习

出0入0汤圆

发表于 2008-8-27 08:28:57 | 显示全部楼层
.

出0入0汤圆

发表于 2008-8-27 08:29:04 | 显示全部楼层
业余也能这样.牛啊!

出0入0汤圆

发表于 2008-8-27 14:09:23 | 显示全部楼层
标记

出0入0汤圆

发表于 2008-8-27 15:42:23 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-8-28 08:07:22 | 显示全部楼层
好,好!

出0入0汤圆

发表于 2008-8-28 12:35:54 | 显示全部楼层
LZ精神可佳
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-28 04:59

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表