SDL实例-1、打砖块

1、前言

本文实现了“打砖块”游戏的基本逻辑,算是一个小demo。开发环境配置可参考我的“SDL基础”系列文章,游戏截图如下:

这里写图片描述

2、代码

#include <stdbool.h>//使用bool类型
#include <stdio.h>
#include <stdlib.h>
#include <math.h>//数学库,用于计算两点间距离,判断是否发生碰撞
#include <SDL2/SDL.h>//引用SDL库
#include <SDL2/SDL_image.h>//引用SDL_image库
//屏幕属性
#define WINDOW_WIDTH  320//屏幕宽度
#define WINDOW_HEIGHT  600//屏幕长度


//位置
SDL_Rect BlueRect ; //砖块
SDL_Rect BallRect ; //球
SDL_Rect ReboundRodsRect ; //反弹棒

//事件
SDL_Event event;

//指针
SDL_Window* window = NULL;

SDL_Renderer* renderer = NULL;

SDL_Surface* BallSueface = NULL;
SDL_Surface* ReboundRodsSurface = NULL;
SDL_Surface* BlueBrick = NULL;//砖块
SDL_Surface* breakBlue = NULL;//打碎的砖块


SDL_Texture* BlueBrickTT;
SDL_Texture* breakBlueTT;
SDL_Texture* BallTT = NULL;
SDL_Texture* ReboundRodsTT = NULL;
//结构体

typedef struct SSurface//砖块结构体
{
    SDL_Texture* Texture;//文理
    SDL_Rect TargetRect;//目标rect
    SDL_Rect SourceRect;//源图片的rect
    int index;//显示那张图片
    bool state;//是否有效
}SSurface;
SSurface BlickManager[10][5];//结构体数组,存放方砖结构体

//全局参数
const int BrickW = 64;//砖块的宽度
const int BrickH = 32;//砖块的高度
//球移动速度
int ReboundRodsSpeed = 3;//反弹棒移动速度
int BallSpeed = 2;//小球移动速度

//控制反弹棒的移动方向
bool moveReboundRodsLeft = false;//反弹棒左移标志位
bool moveReboundRodsRight = false;//反弹棒右移标志位
//控制球的移动方向
bool moveRight = true;
bool moveDown = true;

//子函数
void init(void);//初始化函数
void UpdateLogic(void);//更新逻辑
void draw(void);//画图
int check_collision();//检查球与砖块的碰撞,还有瑕疵待修正
bool checkCollision(SDL_Rect A,SDL_Rect B);//球与反弹棒相撞检测,暂不去除
double GetDistance(int x1,int y1,int x2,int y2);//返回两点距离

int main(int argc,char* argv[])
{
    init();//初始化
    bool quit = false;//跳出循环后执行quit(),确保资源的释放
    while(quit == false)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)//退出事件
            {
                quit = true;
            }
            else if(event.type == SDL_KEYDOWN)//键盘事件
            {
               if(event.key.keysym.sym == SDLK_LEFT)//左移动
               {
                   moveReboundRodsLeft = true;
               }
                else if(event.key.keysym.sym == SDLK_RIGHT)//右移动
               {
                   moveReboundRodsRight = true;
               }
            }
            else if(event.type == SDL_KEYUP)
            {
                if(event.key.keysym.sym == SDLK_LEFT)//左移动取消
               {
                   moveReboundRodsLeft = false;
               }
                 else if(event.key.keysym.sym == SDLK_RIGHT)//右移动取消
               {
                   moveReboundRodsRight = false;
               }
            }

        }
        UpdateLogic();//更新逻辑
        SDL_RenderClear(renderer);//清除画布
        draw();//绘图
        SDL_RenderPresent(renderer);//刷新
        SDL_Delay(10);//释放CPU,解决CPU占用过多的问题
    }

    SDL_FreeSurface(BlueBrick);
    SDL_FreeSurface(BallSueface);
    //SDL_DestroyTexture()
    //SDL_DestroyRenderer()
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

bool checkCollision(SDL_Rect A,SDL_Rect B)
{
    //矩形的各边
    int leftA,leftB;
    int rightA,rightB;
    int topA,topB;
    int bottomA,bottomB;
    //计算rect A的各边
    leftA = A.x;
    rightA = A.x+A.w;
    topA = A.y;
    bottomA = A.y+A.h;
    //计算 rect B的各边
    leftB = B.x;
    rightB = B.x+B.w;
    topB = B.y;
    bottomB = B.y + B.h;

    //如果A的任意一边的位置在B的外面     
    if(bottomA <= topB)
    {
        return false;
    }
    if(topA >= bottomB)
    {
        return false;
    }

    if(rightA <= leftB)
    {
        return false;
    }
    if(leftA >= rightB)
    {
        return false;
    }
    return true;//如果A的各边全都不在B的外面
}


void UpdateLogic(void)
{
    //更新图片,如果index=2,说明碰撞,更换碎裂的图片
    int x,y;
    for(x = 0; x < 10; x++)
    {
        for(y = 0;y < 5; y++)
        {
            if(BlickManager[x][y].state == true)
            {
                if(BlickManager[x][y].index == 2)
                {
                    BlickManager[x][y].Texture = breakBlueTT;
                    BlickManager[x][y].SourceRect.x = 0;
                    BlickManager[x][y].SourceRect.y = 0;
                    BlickManager[x][y].index+=1;
                }
                else if(BlickManager[x][y].index == 3)
                {
                    BlickManager[x][y].SourceRect.x = BrickW;
                    BlickManager[x][y].SourceRect.y = 0;
                    BlickManager[x][y].index+=1;
                }
                else if(BlickManager[x][y].index == 4)
                {
                    BlickManager[x][y].SourceRect.x = BrickW*2;
                    BlickManager[x][y].SourceRect.y = 0;
                    BlickManager[x][y].index+=1;
                }
                else if(BlickManager[x][y].index == 5)
                {
                    BlickManager[x][y].SourceRect.x = BrickW*3;
                    BlickManager[x][y].SourceRect.y = 0;
                    BlickManager[x][y].index+=1;
                }
                else if(BlickManager[x][y].index == 6)
                {
                    BlickManager[x][y].SourceRect.x = BrickW*4;
                    BlickManager[x][y].SourceRect.y = 0;
                    BlickManager[x][y].index=1;
                    BlickManager[x][y].state = false;
                }
            }
        }
    }






    //球的运动轨迹控制
    if(true == moveRight)
    {
        BallRect.x=BallRect.x+BallSpeed;
        if((BallRect.x + BallRect.w >=WINDOW_WIDTH)||(1 == check_collision()) )
        //if(BallRect.x + BallRect.w >=WINDOW_WIDTH)
        {
            moveRight = false;
            //printf("trun left\n");
        }
    }
    else
    {
        BallRect.x=BallRect.x-BallSpeed;
        if((BallRect.x <= 0)||(2 == check_collision()) )
        //if(BallRect.x <= 0)
        {
            moveRight = true;
            //printf("trun right\n");
        }
    }

    if(true == moveDown)
    {
        BallRect.y=BallRect.y+BallSpeed;
        if(BallRect.y + BallRect.h >=WINDOW_HEIGHT||checkCollision(BallRect,ReboundRodsRect)||(3 == check_collision()) )
        {
            moveDown= false;
            //printf("trun up\n");
        }
    }
    else
    {
        BallRect.y=BallRect.y-BallSpeed;
        if(BallRect.y <= 0||4 == check_collision() )
        //if(BallRect.y <= 0)
        {
            moveDown = true;
            //printf("trun down\n");
        }
    }

    //反弹棒的运动轨迹控制
    if(moveReboundRodsLeft == true)//反弹棒左移
        {
            if(ReboundRodsRect.x > 0)
            {
                ReboundRodsRect.x = ReboundRodsRect.x - ReboundRodsSpeed ;
            }

        }
    if(moveReboundRodsRight == true)//反弹棒右移
        {
            if(ReboundRodsRect.x + ReboundRodsRect.w < WINDOW_WIDTH )
            {
                ReboundRodsRect.x = ReboundRodsRect.x + ReboundRodsSpeed ;
            }

        }
}
void draw(void)
{
    int i,j;
    for(i = 0; i < 10; i++)
    {
        for(j = 0;j < 5; j++)
        {
            if(BlickManager[i][j].state == true)
            {
                SDL_RenderCopy(renderer,BlickManager[i][j].Texture,&BlickManager[i][j].SourceRect,&BlickManager[i][j].TargetRect);
            }
        }
    }

    SDL_RenderCopy(renderer,BallTT,NULL,&BallRect);//贴球文理
    SDL_RenderCopy(renderer,ReboundRodsTT,NULL,&ReboundRodsRect);//贴反弹棒文理
}

void init(void)
{
    SDL_Init(SDL_INIT_VIDEO);
    window = SDL_CreateWindow("MakeBricks",100,100,WINDOW_WIDTH,WINDOW_HEIGHT,SDL_WINDOW_SHOWN);

    renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);//创建渲染
    SDL_RenderClear(renderer);

    //加载图片
    BallSueface = IMG_Load("res/ball_pinball.png");

    ReboundRodsSurface = IMG_Load("res/bat_large.png");

    BlueBrick = IMG_Load("res/Stones/stone_glow_blue.png");//完整的砖块图片

    breakBlue = IMG_Load("res/Stones/stone_breaking_blue_strip5.png");//砖块碎裂效果图,5幅

    BallTT          = SDL_CreateTextureFromSurface(renderer,BallSueface);//创建球文理

    ReboundRodsTT   = SDL_CreateTextureFromSurface(renderer,ReboundRodsSurface);//创建反弹棒文理

    BlueBrickTT  = SDL_CreateTextureFromSurface(renderer,BlueBrick);//创建完整砖块文理

    breakBlueTT = SDL_CreateTextureFromSurface(renderer,breakBlue);//创建碎裂砖块效果图文理

    BallRect.x = WINDOW_WIDTH/2-(BallSueface->w/2);
    BallRect.y = WINDOW_HEIGHT/10*9-BallSueface->h;
    BallRect.w = BallSueface->w;//采用渲染,必须要设置长、宽
    BallRect.h = BallSueface->h;

    ReboundRodsRect.x = WINDOW_WIDTH/2-(ReboundRodsSurface->w/2);
    ReboundRodsRect.y = WINDOW_HEIGHT/10*9;
    ReboundRodsRect.w = ReboundRodsSurface->w;
    ReboundRodsRect.h = ReboundRodsSurface->h;

    BlueRect.x = 0;
    BlueRect.y = 0;
    BlueRect.w = BlueBrick->w;//采用渲染,必须要设置长、宽
    BlueRect.h = BlueBrick->h;

    //砖块数组赋值
    int i,j;
    for(i = 0; i < 10; i++)
    {
        for(j = 0;j < 5; j++)
        {
            BlickManager[i][j].Texture = BlueBrickTT;

            BlickManager[i][j].SourceRect = BlueRect;

            BlickManager[i][j].TargetRect.x = BrickW*j;
            BlickManager[i][j].TargetRect.y = BrickH*i;
            BlickManager[i][j].TargetRect.w = BlueRect.w;
            BlickManager[i][j].TargetRect.h = BlueRect.h;

            BlickManager[i][j].state = true;
            BlickManager[i][j].index = 1;
        }
    }
}

double GetDistance(int x1,int y1,int x2,int y2)
{
    double distance = sqrt((double)(pow(x2-x1,2)+pow(y2-y1,2)));
    return distance;
}

int check_collision()
{
    int x = 0;// 矩形上的最近点x轴坐标
    int y = 0;//矩形上的最近点y轴坐标

    int cx = BallRect.x+BallRect.w/2;//圆心的x轴坐标
    int cy = BallRect.y+BallRect.h/2;//圆心的y轴坐标
    int cr = BallRect.w/2;//圆半径

    int i;//循环变量
    int j;//循环变量
    for(i = 0 ; i < 10 ; i++)
    {
        for(j = 0 ; j<5 ; j++)
        {
            if(BlickManager[i][j].state == true)//如果状态位真,判断是否碰撞
            {

                      //寻找最近的X位置
                if(cx < BlickManager[i][j].TargetRect.x)
                {
                    x = BlickManager[i][j].TargetRect.x;
                }
                else if(cx > BlickManager[i][j].TargetRect.x+BlickManager[i][j].TargetRect.w)
                {
                    x = BlickManager[i][j].TargetRect.x+BlickManager[i][j].TargetRect.w;
                }
                else
                {
                    x = cx;
                }

                   //寻找最近的Y位置
                if(cy < BlickManager[i][j].TargetRect.y)
                {
                    y = BlickManager[i][j].TargetRect.y;
                }
                else if(cy > BlickManager[i][j].TargetRect.y+BlickManager[i][j].TargetRect.h)
                {
                    y = BlickManager[i][j].TargetRect.y+BlickManager[i][j].TargetRect.h;
                }
                else
                {
                    y = cy;
                }

                if( GetDistance(cx,cy,x,y) <= cr)//当两点距离小于半径时,发生碰撞
                {
                    //BlickManager[i][j].state = false;
                    BlickManager[i][j].index = 2;//设置该砖块显示破裂图片
                    if(cx<x&&y>=BlickManager[i][j].TargetRect.y&&y<=BlickManager[i][j].TargetRect.y+BrickH)//碰到左边
                    {
                        //printf("touch left\n");
                        return 1;
                    }else if(cx>x&&y>=BlickManager[i][j].TargetRect.y&&y<=BlickManager[i][j].TargetRect.y+BrickH)//碰到右边
                    {
                        //printf("touch right\n");
                        return 2;
                    }
                    else if(cy<y&&x>=BlickManager[i][j].TargetRect.x&&x<=BlickManager[i][j].TargetRect.x+BrickW)//碰上边
                    {
                        //printf("touch top\n");
                        return 3;
                    }
                    else if(cy>y&&x>=BlickManager[i][j].TargetRect.x&&x<=BlickManager[i][j].TargetRect.x+BrickW)//碰下边
                    {
                        //printf("touch button\n");
                        return 4;
                    }
                    else
                    {
                        //printf("x:%d...y:%d\n",x,y);
                    }
                }
            }
        }
    }

    return 0;
}

3、后记

目前代码还没有优化。碰撞检查还有点小瑕疵。如果有朋友感兴趣,并优化,可留言交流,谢谢。
另:需要代码的朋友可以告诉我怎么在文章里放置下载吗?有些朋友需要,不能一一回复,想统一放一个下载地址,谢谢。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include #include //用键盘控制精灵移动 int main(int argc, char ** argv) { SDL_Surface * screen; //主表面 SDL_Surface * image; //用来放MM-----的图片信息(像素) SDL_Surface * PlayerImage; //用来测试的图片 SDL_Event event; Uint32 BeginTicks, EndTicks; SDL_Rect PRect, BRect; //PRect对应精灵的移动的小图位置(实现动画),BRect对应精灵在屏幕的位置。 unsigned char PlayerStarts = 0; unsigned char PlayerIndex = 0; bool bAppRun = true; //初始化SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) { fprintf(stderr, "SDL_Init %s\n", SDL_GetError()); return -1; } //初始化成功设置退出要调用的函数SDL_Quit atexit(SDL_Quit); //创建一个640X480 16-bit 模式的主表面 16位可以让MM的效果好看一点 screen = SDL_SetVideoMode(230, 230, 16, SDL_SWSURFACE); if (screen == NULL) { fprintf(stderr, "Couldn't set 640x480x8 video mode %s\n", SDL_GetError()); return -1; } //读取MM图片信息,并创建一个表面,并把数据填入该表面中。 image = SDL_LoadBMP("./mm.bmp"); //请在终端里运行该程序 if (image == NULL) { fprintf(stderr, "Couldn't load MM, %s\n", SDL_GetError()); //遗憾你不能显示MM了,不过你可以用图片浏览程序看。 return -1; } //读取player.bmp PlayerImage = SDL_LoadBMP("./player.bmp"); //请在终端里运行该程序 if (image == NULL) { fprintf(stderr, "Couldn't load MM, %s\n", SDL_GetError()); //遗憾你不能显示MM了,不过你可以用图片浏览程序看。 return -1; } //读取第一个像素 Uint8 key = *((Uint8 *)PlayerImage->pixels); //设置色键 SDL_SetColorKey(PlayerImage, SDL_SRCCOLORKEY, key); //有了MM的表面了,就可以显示了。 //将MM的表面画在我们的主表面上,用MM来作为背景 if (SDL_BlitSurface(image, NULL, screen, NULL) < 0) { //解释一下NULL,第一个是按照image的尺寸显示,第二个是默认显示。你也可以指定大小,不过要用到SDL_Rect你可以看一看帮助。 fprintf(stderr, "BlitSurface error: %s\n", SDL_GetError()); //看看提示吧 return -1; } PRect.x = 0; //初始化动画显示的图片。 PRect.y = 0; PRect.w = 32; PRect.h = 48; BRect.x = 0; //初始化精灵的位置。 BRect.y = 0; BRect.w = 32; BRect.h = 48; //贴上测试用的表面 if (SDL_BlitSurface(PlayerImage, &PRect, screen, &BRect) w, image->h); BeginT

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值