一 视频游戏要做哪些方面
- 空间—屏幕的展示与控制
- 时间—如何控制物体的移动—什么时间出现什么样的物体
- 中断----用户的操作如何进行中断
- 同时的做几件事----又控制物体的移动,又实时接收操作的输入
二 屏幕空间的控制
- curses库—编译时记得gcc的so库链接方式
mvaddch()函数 - refresh如何修改屏幕显示
在进程中有两个虚拟屏幕:一个是真实屏幕的复制;另一个是工作屏幕。所有函数进行修改都是在工作屏幕中进行的,然后对比真实屏幕cp版和工作屏幕,修改真实屏幕copy版------只传输改变的内容,而不是影像本身
三 时间的精确控制
Alarm
- sleep本身就调用了alarm函数----alarm的单位是秒
- 系统中的每一个进程都在内核中有一个私有的闹钟,调用alarm函数时会给该闹钟定时,时间一到,内核中的闹钟就会响,然后给进程发送信号,进程利用signal函数对信号进行处理
间隔计时器
- alarm的精度不够及一些缺点—》usleep函数(以微秒为单位)----》出现了功能更多的间隔计时器(interval timer)
- 每一个进程有三个计时器—每个计时器都有两个设置—一个是初始间隔,还有一个重复间隔时间。
- 三个计时器的功能:
- 步骤:对itimerval结构体进行赋值设置----->然后通过setitimer函数传给内核中的计时器(哪个计时器由setitimer的参数决定)
四 中断
- signal信号有时不能满足任务的需求—比如阻塞信号等等
- 所以有了sigaction函数与sigaction结构体
- 数据损毁----临界区代码(不能被打断执行的代码称为临界区)被打断就会产生数据损毁-----解决方法:阻塞信号或者忽略
- 在sigaction结构体中很重要的一个变量便是sa_mask变量,该变量控制阻塞哪些信号,被阻塞的信号,在进程的任务完成后,会接收被阻塞的信号。信号阻塞详解
- sigemptyset----sigaddset----sigfillset----sigdelset------>sigprocmask函数
注意:程序中对资源修改完毕后,要注意对资源的恢复,这是一个好习惯。
五 视频游戏制作
- 如何控制代码中不同资源的不同运行速度—通过在程序中虚拟计时器实现—以进程的基本计时器为基准----类似时针分针和秒针
- 例如在球的竖直与水平运动中----控制球的斜向运动-----需要为数竖直与水平方向的运动各维持一个结构体,在结构体中虚拟出计时器的两个时间
六 异步输入
- 什么是异步:发送一个请求,不必等待,可以去做其他事情
- 什么是异步输入:键盘进行输入,输入作为一个信号,不必立即处理(信号阻塞),等待进程空闲,来接收该信号
- 键盘的信号控制:
- aio_read函数+aiocb结构体—将设置好的结构体传给aio_read函数—记得gcc链接时链接rt的动态库
七 总结
- 空间:curses库来进行控制
- 时间:signal的SIGALRM信号+间隔计时器----设置好信号处理函数,以及计时器设置函数
- 信号中断:异步输入—>signal的SIGIO信号
- 多过程同时进行:多线程----多信号
#include<stdio.h>
#include<ncurses.h>
#include<signal.h>
#include<sys/time.h>
#define MSG 'o'
#define BLK ' '
#define TOP 5
#define BOT 20
#define LEFT 10
#define RIGHT 70
struct ppball{
int y_pos,x_pos,
y_dir,x_dir,
y_ttg,x_ttg,
y_ttm,x_ttm;
char symb;
}ball;
int row,col,x_dir,y_dir;
int set_itimer(float);
int main(){
set_up();
while(1){
int c=getch();
if(c=='w')ball.y_ttm--;
if(c=='s')ball.y_ttm++;
if(c=='a')ball.x_ttm++;
if(c=='d')ball.x_ttm--;
if(c=='q')break;
}
echo();
endwin();
}
void set_up(){
void ball_move();
initscr();
noecho();
crmode();
ball.symb=MSG;
ball.x_dir=ball.y_dir=1;
ball.x_pos=ball.y_pos=10;
ball.x_ttg=ball.x_ttm=5;
ball.y_ttg=ball.y_ttm=8;
signal(SIGINT,SIG_IGN);
mvaddch(ball.y_pos,ball.x_pos,ball.symb);
refresh();
signal(SIGALRM,ball_move);
set_itimer(0.005);
}
int set_itimer(float secs){
struct itimerval tmp;
int sec=secs/1;
float a=(secs-sec);
int usec=a*1000000;
tmp.it_value.tv_sec=sec;
tmp.it_value.tv_usec=usec;
tmp.it_interval.tv_sec=sec;
tmp.it_interval.tv_usec=usec;
return setitimer(ITIMER_REAL,&tmp,NULL);
}
void ball_move(){
int y_cur,x_cur,moved;
signal(SIGALRM,SIG_IGN);
y_cur=ball.y_pos;
x_cur=ball.x_pos;
moved=0;
if(ball.y_ttm>0&&ball.y_ttg--==1){
ball.y_pos+=ball.y_dir;
ball.y_ttg=ball.y_ttm;
moved=1;
}
if(ball.x_ttm>0&&ball.x_ttg--==1){
ball.x_pos+=ball.x_dir;
ball.x_ttg=ball.x_ttm;
moved=1;
}
if(moved){
mvaddch(y_cur,x_cur,BLK);
mvaddch(y_cur,x_cur,BLK);
mvaddch(ball.y_pos,ball.x_pos,ball.symb);
bounce_lose(&ball);
refresh();
}
signal(SIGALRM,ball_move);
}
void bounce_lose(struct ppball*tmp){
if(tmp->y_pos<=TOP&&tmp->y_dir==-1)tmp->y_dir=1;
if(tmp->y_pos>=BOT&&tmp->y_dir==1)tmp->y_dir=-1;
if(tmp->x_pos<=LEFT&&tmp->x_dir==-1)tmp->x_dir=1;
if(tmp->x_pos>=RIGHT&&tmp->x_dir==1)tmp->x_dir=-1;
}