第15章 《乐趣》Page380~386 SDL_Timer的封装,简化代码

//main.cpp
#include <iostream>
#include <SDL2/SDL.h>
#include "sdl_initiator.hpp"
#include "sdl_error.hpp"
#include "sdl_window.hpp"
#include "sdl_surface.hpp"
#include "sdl_renderer.hpp"
#include "sdl_texture.hpp"
#include <SDL2/SDL_timer.h>
#include <thread>
#include "sdl_timer.hpp"

using namespace std;

//加载图片为纹理,并设置透明色
SDL_Texture* LoadBMPTexture(SDL_Renderer* renderer
                           , char const* filename
                           , Uint8 key_r, Uint8 key_g, Uint8 key_b)
{
    sdl2::BitmapSurface bmp(filename);
    if(!bmp)
    {
        return nullptr;
    }
    bmp.EnableColorKey(key_r, key_g, key_b, 0);
    return sdl2::Texture(renderer, bmp._surface).Release();
}
//加载图片为纹理,不透明,不混色
SDL_Texture* LoadBMPTexture(SDL_Renderer* renderer
                            , char const* filename)
{
    sdl2::BitmapSurface bmp(filename);
    if(!bmp)
    {
        return nullptr;
    }

    return sdl2::Texture(renderer, bmp._surface).Release();
}
//加载图片为纹理,并设置透明色和混色
SDL_Texture* LoadBMPTexture(SDL_Renderer* renderer
                , char const* filename
                , Uint8 key_r, Uint8 key_g, Uint8 key_b
                , Uint8 alpha_mod
                , SDL_BlendMode blend_mode = SDL_BLENDMODE_BLEND)
{
    sdl2::BitmapSurface bmp(filename);
    if(!bmp)
    {
        return nullptr;
    }
    bmp.EnableColorKey(key_r, key_g, key_b, 0);
    bmp.SetAlphaMod(alpha_mod);
    bmp.SetBlendMode(blend_mode);
    return sdl2::Texture(renderer, bmp._surface).Release();
}

int main(int argc, char* argv[])
{
    sdl2::Initiator::Instance().Init(SDL_INIT_VIDEO
                                     | SDL_INIT_AUDIO
                                     | SDL_INIT_EVENTS
                                     | SDL_INIT_TIMER);

    if(!sdl2::Initiator::Instance())//重载转换符
    {
        cerr << "初始化就出错,没得玩了!"
             << sdl2::last_error() << endl;
    }

    //创建并居中显示宽640,高480的游戏窗口
    sdl2::Window wnd("hello sdl"
                     , sdl2::WindowPosition()
                     , 640, 480
                     //去除原来的全屏标志
                     , sdl2::WindowFlags());

    if(!wnd)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //准备窗口的渲染器
    sdl2::Renderer renderer(wnd._window);
    if(!renderer)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }
    //重要!修改缩放质量配置
    sdl2::RendererDriver::HintScaleQuality();
    //重要!设置虚拟大小
    renderer.SetLogicalSize(640, 480);

    //准备背景图(不需要透明和混色)
    sdl2::Texture bkgnd(LoadBMPTexture(renderer._renderer, "bkgnd.bmp"));

    if(!bkgnd)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //准备小马图,透明色为白色
    sdl2::Texture horse(LoadBMPTexture(renderer._renderer
                                       , "sdl.bmp"
                                       , 0xff, 0xff, 0xff));
    if(!horse)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //准备白云图纹理,透明色为红色,不透明度188(0~255)
    sdl2::Texture cloud(LoadBMPTexture(renderer._renderer
                                       , "cloud.bmp"
                                       , 0xff, 0, 0, 188));
    if(!cloud)
    {
        cerr << sdl2::last_error() << endl;
        return -1;
    }

    //定时器
    sdl2::Timer timer;

    //小马的宽度
    int w = 0;
    horse.GetSize(&w, nullptr);
    //小马的起始位置,靠左侧站立
    SDL_Rect horse_rect{-w, 65, 468, 350};

    //事件循环
    bool Q = false;
    while(!Q)//一直循环,直到Q为真
    {
        SDL_Event event;
        //会将队列中拖出的event数据存储到event中
        while(SDL_PollEvent(&event))
        {
            switch(event.type)
            {
                case SDL_QUIT:
                    Q = true;
                    break;

                case SDL_KEYDOWN:
                                                    //即timer为空
                    if(event.key.keysym.sym == SDLK_t && !timer)//按键 ctrl + t,
                    {
                        int const horse_run_timer_code = 1;
                        timer.Start(500, horse_run_timer_code);
                    }
                    break;
                case SDL_USEREVENT: //定时事件(用户自定义事件)
                    if(event.user.code == 1)
                    {
                        if(horse_rect.x <= 640)
                            horse_rect.x += 15;
                        else //出最右边了
                            timer.Stop();
                    }
                    break;
            }
        }//内循环

        /*外循环:贴骏马图*/
        //贴背景->窗口
        renderer.CopyFrom(bkgnd._texture);

        //贴第一朵白云
        SDL_Rect cloud_rect_1{200, 20, 156, 78};
        renderer.CopyFrom(cloud._texture, nullptr, &cloud_rect_1);

        //贴第二朵白云
        SDL_Rect cloud_rect_2{340, 6, 156, 78};
        renderer.CopyFrom(cloud._texture, nullptr, &cloud_rect_2);
        //贴骏马
//        SDL_Rect dst_rect{86, 65, 468, 350};
        renderer.CopyFrom(horse._texture, nullptr, &horse_rect);

        renderer.Present();
        sdl2::Timer::Delay(1);//防止cpu占用率太高
//        Q = true; //开发过程中,为方便程序退出,暂时这样
    }//外循环

    return 0;
}

//sdl_timer.hpp
#ifndef SDL_TIMER_HPP_INCLUDED
#define SDL_TIMER_HPP_INCLUDED

namespace sdl2
{

struct Timer
{
    Timer()
        : _timer_id(0)
        , _interval(0)
        , _event_code(0)
        , _user_data(nullptr)
    {

    }

    ~Timer()
    {
        if(_timer_id != 0)
        {
            SDL_RemoveTimer(_timer_id);
        }
    }

    //顺便封装SDL_Delay(),静态方法
    static void Delay(Uint32 ms)
    {
        SDL_Delay(ms);
    }

    bool Start(Uint32 interval
               , Sint32 event_code = 0
               , void* data = nullptr)
    {
        if(_timer_id != 0)//已经创建过了
        return false;

        this->_user_data = data;
        this->_interval = interval;
        this->_event_code = event_code;

        //添加定时器
        _timer_id = SDL_AddTimer(interval
                                 , &Timer::Callback//回调
                                   //回调函数中需要创建一个SDL_Event,需要
                                   //用到this的数据,所以需要把this传递过去
                                 , this); //定时器用户数据固定为this
        return (_timer_id != 0);
    }

    //结束(移除)内部定时器
    void Stop()
    {
        if(_timer_id != 0)
        {
            SDL_RemoveTimer(_timer_id);
            _timer_id = 0;
        }
    }

    explicit operator bool() const
    {
        return _timer_id != 0;
    }

private:
    static Uint32 Callback(Uint32 interval, void* param)
    {
        Timer* self = static_cast <Timer*> (param);
        if(!self)
            return 0;

        SDL_Event event;
        event.type = SDL_USEREVENT;
        event.user.code = self->_event_code; //事件二级分类
        //注意:事件的data被征用
        //总是被用于记录定时器对象
        event.user.data1 = self;
        //data2才是用户自定义事件数据(可有可无)
        event.user.data2 = self->_user_data;

        if(1 != SDL_PushEvent(&event))
        {
            self->_timer_id = 0;
            return 0; //添加事件失败,结束定时
        }

        return interval;
    }
private:
    SDL_TimerID _timer_id;
    Uint32 _interval;
    Sint32 _event_code;
    void* _user_data;
};

}//sdl2

#endif // SDL_TIMER_HPP_INCLUDED

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值