使用SDL2.0编写一个模拟电话拨号盘的程序
来源:互联网 发布:淘宝退款率多久清零 编辑:程序博客网 时间:2024/05/22 21:08
这次更新的是一个关于使用SDL编写模拟电话拨号盘的程序。
下面先来描述一下这个程序需要实现的功能:
在这次的程序中,我们将要实现的功能是拨动拨号盘,在拨动期间会伴有拨号声音,并且在拨号完后会显示出号码。
下面是我们将要用到的一些图片资源:
这是我在网上找的一张图片,作为我们整个程序的原始图片,后面我们需要的图片要从它上面进行ps提取,首先我们要把它中间的那个圆盘给p下来,保存成一张透明的png图片,同样将那个黑色的卡条给p下来,保存成一张透明的png图片,这里我就不贴上来了,因为图片太大了,待会我会在文章最后附上我全部程序资源的百度云网址,供大家下载。
下面简要说一下此程序需要用到的技术:
1、对于如何加载窗口和进行事件响应的工作我在这里就不再说明了,如果有什么问题可以参考我的上一篇博客,里面有相关的说明。
2、我们首先来实现拨号的功能,也就是如何让中间的拨号盘可以转动起来。我这里使用的方法是用将中间的拨号盘的图片扣出来,做成一张周围透明的图片(这些图片的加载 需要用到SDL_Image库),覆盖在原始的电话机上,并使用这个抠出来的图片响应鼠标的拖动,以实现拨号的功能,这里面将会使用到一个函数SDL_RenderCopyEx,这个函数可以参照我的另一篇文章:http://blog.csdn.net/qq_29883591/article/details/52924047。
3、然后我们要实现拨号声音,这里面我们将会使用SDL_Mixer库,这个可以参照我的另一篇博客:http://blog.csdn.net/qq_29883591/article/details/52913658,对于我程序中用到的音乐只有不到1秒钟,所以在拨号期间我得记录时间间隔并重复播放音乐。
4、实现号码的展示,这里我偷了个懒,没有使用真实数字的展示,而是通过带数字的图片进行展示的,大家有兴趣的话可以自己去实现下真实的字。
下面直接上代码,里面有很清楚的注释:
#include<iostream>#include<SDL/SDL.h>#include<SDL/SDL_Image.h>#include<SDL\SDL_mixer.h>#include<string>#include<time.h>#include<stdlib.h>#include<vector>using namespace std;SDL_Renderer *renderer = nullptr;SDL_Window *window = nullptr;const int SCREEN_WIDTH = 1000;const int SCREEN_HEIGHT = 668;//buttons用于记录电话盘上0到9的圆心坐标const int buttons[10][10]={{692,551},{696,344},{641,334},{590,344},{552,378},{530,424},{530,475},{554,522},{592,552},{645,564}};const int radius=20; //代表电话盘上圆心的半径int phoneNumber[11]; //中国的号码最多11位int index=0; //用于记录号码的个数SDL_Texture *number[10]; //存放10个数字的图片//此函数用于加载图片SDL_Texture* LoadImage(std::string file);//此函数用于将纹理画到渲染器上void ApplySurface(int x, int y, SDL_Texture *tex, SDL_Renderer *rend);//此函数用于判断鼠标是否按在了0到9这10个数字中的一个,如果是,则返回这个数字的值,否则返回-1int check(int mouse_x,int mouse_y);//此函数用于计算两个向量之间的夹角,运用的是余弦定理和反余弦函数求角度double calDegree(int x1,int y1,int x2,int y2);//计算第二个向量相对于第一个向量旋转的方向,用的是向量叉乘定理bool direct(int x1,int y1,int x2,int y2);//此函数用于显示我们将要展示的图形界面void show(SDL_Texture *phone,SDL_Texture *dialdial,SDL_Texture *button,int angle,SDL_Point center);//此函数用于加载十个数字void initNumber();//销毁十个数字的图片void destroyNumber();int main(int argc,char *argv){if (SDL_Init(SDL_INIT_EVERYTHING) == -1){ std::cout << SDL_GetError() << std::endl; return 1; } window = SDL_CreateWindow("LightDemo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); //创建一个绘制图片的窗口 if (window == nullptr){ std::cout << SDL_GetError() << std::endl; return 2; }renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); //创建一个指定到窗口的渲染器 if (renderer == nullptr){ std::cout << SDL_GetError() << std::endl; return 3; }SDL_Texture *phone = nullptr, *dial = nullptr,*button=nullptr; try {//用于加载电话机的整体图片phone=LoadImage("phone.jpg");//用于加载电话的拨号盘 dial = LoadImage("dial.png");//用于加载拨号盘上的挂钩button=LoadImage("button.png"); }catch (const std::runtime_error &e){std::cout << e.what() << std::endl;return 4; } initNumber(); //加载0到9这10张图片double angle=0; //angle代表旋转的角度SDL_Point center; //center用于表示dial图片的圆心center.x=644;center.y=448;//加载声音文件Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,2048); Mix_Music *sound=Mix_LoadMUS("D://sound.wav");time_t start,end=0; //用于标识时间的起始,在后面我们在配音的时候会用到time_t timeDist=0; //此变量用于表示start和end的差值 SDL_Event e;bool quit=false; //用于标记用户是否想退出程序bool mouseDown=false; //此变量用于指示鼠标是否一直按着没有松开int downButton=-1; //此变量用于标识用户在拨动的号码//下面两组变量用于存储两个不同时刻鼠标的位置int mouse_x,mouse_y; int curMouse_x; int curMouse_y;bool flag; //flag用于标识拨号盘的号码键是否被成功拨到底端,成功拨号置为true,否则为falseshow(phone,dial,button,angle,center);while(!quit){while(SDL_PollEvent(&e)){switch(e.type){ //此种情况是退出程序用的,当你点击窗口的红X时就会关闭界面case SDL_QUIT: quit=true;break;//此处处理的是鼠标按下事件case SDL_MOUSEBUTTONDOWN:mouseDown=true;mouse_x=e.button.x;mouse_y=e.button.y;downButton=check(mouse_x,mouse_y); //记下当前鼠标按下的数字(当然也可能为-1,即没有按在数字上)show(phone,dial,button,angle,center);start=clock(); //记录下起始时间,以便播放声音break;//鼠标弹起操作case SDL_MOUSEBUTTONUP:while(angle>=0) //此时angle大于0则表示拨号盘被松开了且没有回到原位置,则动态展示拨号盘自动转回来的场景{show(phone,dial,button,angle,center);angle-=2; //设置每次转动角度为2end=clock(); //记录下时间if(difftime(end,start)-timeDist>800) //当时间过了800毫秒时,重新播放音乐{timeDist+=800;Mix_PlayMusic(sound,1);}}if(angle<=0)end=0; //当拨号盘转回到初始位置时,将结束时间清0mouseDown=false; //记录下鼠标没有按下timeDist=0; //时间间隔清0break; //处理鼠标移动case SDL_MOUSEMOTION:{//记录下鼠标移动过程中位置的坐标curMouse_x=e.motion.x;curMouse_y=e.motion.y;if(mouseDown) //当鼠标按下去时,此时即是鼠标在拖动{//此处的75+downButton*27是根据拨号盘中数字的位置计算每个数字可以被转动的角度,当到极限时不允许转动,此时即拨号成功if(downButton!=-1&&angle<75+downButton*27) {if(end==0) //当拨号盘从初始位置转动时,播放音乐 Mix_PlayMusic(sound,1);end=clock(); //记录下时间,以便计算时间间隔flag=false;int vec1_x=mouse_x-center.x;int vec1_y=mouse_y-center.y;int vec2_x=curMouse_x-center.x;int vec2_y=curMouse_y-center.y;if(direct(vec1_x,vec1_y,vec2_x,vec2_y)) //计算鼠标旋转的方向,顺时针时才可以拨动号码盘 angle+=calDegree(vec1_x,vec1_y,vec2_x,vec2_y);show(phone,dial,button,angle,center);//SDL_Delay(20);//将当前鼠标的位置赋值给记录前一次移动鼠标的位置,以便进行迭代 mouse_x=curMouse_x;mouse_y=curMouse_y;//当时间过了800毫秒时,重新播放音乐if(difftime(end,start)-timeDist>800){timeDist+=800; Mix_PlayMusic(sound,1);}}else if(!flag&&angle>75+downButton*27) //此时代表拨号成功{flag=true;//将号码存储在数组中if(downButton==10) //10代表的是数字0 phoneNumber[index]=0; else phoneNumber[index]=downButton;index++;//当号码的位数超过11位时,清空if(index>=11)index=0;}}}break;//处理默认的操作default:break;}} } SDL_DestroyTexture(phone); SDL_DestroyTexture(dial); SDL_DestroyTexture(button); SDL_DestroyRenderer(renderer); destroyNumber(); SDL_DestroyWindow(window); return 0;}//此函数用于加载十个数字void initNumber(){number[0]=LoadImage("0.png"); number[1]=LoadImage("1.png"); number[2]=LoadImage("2.png");number[3]=LoadImage("3.png");number[4]=LoadImage("4.png");number[5]=LoadImage("5.png");number[6]=LoadImage("6.png");number[7]=LoadImage("7.png");number[8]=LoadImage("8.png");number[9]=LoadImage("9.png");}void destroyNumber(){for(int i=0;i<9;i++){SDL_DestroyTexture(number[i]);}}//此函数用于加载图片SDL_Texture* LoadImage(std::string file){ SDL_Texture* tex = nullptr; tex = IMG_LoadTexture(renderer, file.c_str()); if (tex == nullptr) throw std::runtime_error("Failed to load dial: " + file + IMG_GetError()); return tex;}//此函数用于将纹理画到渲染器上void ApplySurface(int x, int y, SDL_Texture *tex, SDL_Renderer *rend){ SDL_Rect pos;//x,y是图片左上角的坐标 pos.x = x; pos.y = y; SDL_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h); SDL_RenderCopy(rend, tex, NULL, &pos); //将纹理tex画到渲染器rend}//此函数用于判断鼠标是否按在了0到9这10个数字中的一个,如果是,则返回这个数字的值,否则返回-1int check(int mouse_x,int mouse_y){double dist;for(int i=0;i<10;i++){//dist存储的值为鼠标到圆形数字圆心的距离dist=sqrt(double((mouse_x-buttons[i][0])*(mouse_x-buttons[i][0])+(mouse_y-buttons[i][1])*(mouse_y-buttons[i][1])));if(dist<=radius) //当距离小于半径时,则表示鼠标触碰到了数字{if(i==0) //此处将0处理成10是为了后面旋转拨号时角度的处理方便return 10;return i;}}return -1;}//此函数用于计算两个向量之间的夹角,运用的是余弦定理和反余弦函数求角度double calDegree(int x1,int y1,int x2,int y2){int n=x1*x2+y1*y2;double m=sqrt(double(x1*x1+y1*y1))*sqrt(double(x2*x2+y2*y2));return acos(n/m)*180/3.14;}//计算第二个向量相对于第一个向量旋转的方向,用的是向量叉乘定理bool direct(int x1,int y1,int x2,int y2){int n=x1*y2-x2*y1;return n>=0; //n大于0表示顺时针,否则表示逆时针}//此函数用于显示我们将要展示的图形界面void show(SDL_Texture *phone,SDL_Texture *dialdial,SDL_Texture *button,int angle,SDL_Point center){SDL_RenderClear(renderer);ApplySurface(0,0,phone,renderer);SDL_RenderCopyEx(renderer, dialdial, NULL,NULL, angle, ¢er, SDL_FLIP_NONE);//下面的循环用于在界面上显示拨打的号码for(int i=0;i<index;i++){ApplySurface(30+30*i,450,number[phoneNumber[i]],renderer);}SDL_RenderPresent(renderer);}
程序的所有相关资源放在了网盘,链接为:http://pan.baidu.com/s/1pLdF6BL。
- 使用SDL2.0编写一个模拟电话拨号盘的程序
- 一个SDL2.0程序的分析
- 编写一个模拟航空客运定票系统的程序
- 编写一个程序,模拟扔硬币的结果.
- 电话源码拨号盘控件
- ffmpeg+sdl2.0编写最简单的视频播放器
- SDL2.0 使用互斥量
- OpenGL的SDL2接入程序
- sdl2.0的按钮控件实现原理小程序
- ffmpeg+sdl2.0做一个简单的音频播放器
- ffmpeg+sdl2.0做一个简单的音频播放器
- 电话拨号盘T9搜索原理
- SDL2.0 多线程使用信号量
- 一个使用JAVA编写的类似按键精灵的程序
- 一个使用JAVA编写的类似按键精灵的程序
- 用c#编写的一个简单的模拟“蛇吞食”程序
- 使用C#编写的一个定时关机程序
- 使用C#编写的一个定时关机程序
- ViewDragHelper拖拽----类似天天静听拖拽隐藏歌词界面
- 如何让EditText不自动获取焦点
- Js前端
- MySQL基础(一)
- python list 取倒序
- 使用SDL2.0编写一个模拟电话拨号盘的程序
- 运算符两边操作数一定是同类型的
- 【Linux 内核网络协议栈源码剖析】recvfrom 函数剖析
- 字符流输出(写)案例
- LAMP环境搭建
- while 后面没有;
- Int转byte类型转换的笔试题
- 八种常见排序算法
- Java BigDecimal详解