May 12

SDL(Simple DirectMedia Layer)是一套很底层的图形API, 支持Linux, unix, *BSD, MacOS, Win32 and BeOS等平台. 由曾任暴雪公司lead software engineer的Sam Lantinga于1998年创建.

下面, 我在Linux用C语言和SDL编写一个移动图像的程序. 移动图像是2D游戏的基础. 因为SDL也支持Windows, 所以在cygwin下可直接编译运行.

首先. 你需要安装SDL, 也就是下面的包 libsdl, libsdl-dev, libsdl-image, libsdl-image-dev. libsdl-image是一套操作图形文件的的库, 使用它, 你只需要一个函数就能把png, jpg, bmp, gif等文件读入内存, 而且支持png的透明键.

下面是程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//author: ideawu.net
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
 
#define TICK_INTERVAL    15
 
int main(int argc, char *argv[]){
    SDL_Surface *screen;
    SDL_Surface *image;
    SDL_Event event;
    SDL_Rect r = {0,0,0,0};
    int x=0,y=0;
    //使用的图像文件名, 放在当前目录下. 你可以使用png,jpg,bmp,等格式, SDL支持它们.
    char *file_name = "fish.png";
    int timepass=0, timeold=0;
 
    if(SDL_Init(SDL_INIT_VIDEO) < 0){
        printf("Could not initializing SDL: %s.\n",SDL_GetError());
        exit(-1);
    }
    atexit(SDL_Quit);
    screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE|SDL_DOUBLEBUF);
    if(screen == NULL){
        fprintf(stderr, "Couldn't set 800x600x32 video mode: %s\n", SDL_GetError());
        exit(1);
    }
 
    image = IMG_Load(file_name);
    if (image == NULL) {
        fprintf(stderr, "Couldn't load %s: %s\n", file_name, SDL_GetError());
        return 1;
    }
 
    while(SDL_WaitEvent(&event) >= 0){
        switch(event.type){
            case SDL_MOUSEMOTION:
                x = event.motion.x; y = event.motion.y;
                break;
            case SDL_KEYDOWN:
                switch(event.key.keysym.sym){
                    case SDLK_UP:
                        y -= 4;
                        break;
                    case SDLK_DOWN:
                        y += 4;
                        break;
                    case SDLK_LEFT:
                        x -= 4;
                        break;
                    case SDLK_RIGHT:
                        x += 4;
                        break;
                }
                break;
            case SDL_QUIT:
                exit(0);
                break;
        }
        if(x < -image->w + 2) x = -image->w + 2;
        if(y < -image->h + 2) y = -image->h + 2;
        if(x > screen->w + image->w - 2) x = screen->w + image->w - 2;
        if(y > screen->h + image->h - 2) y = screen->h + image->h - 2;
        r.x = x;
        r.y = y;
 
        timeold = SDL_GetTicks();
 
        SDL_FillRect(screen, NULL, 0);
        if(SDL_BlitSurface(image, NULL, screen, &r) < 0)
            fprintf(stderr, "BlitSurface error: %s\n", SDL_GetError());
        SDL_Flip(screen);
        timepass = SDL_GetTicks() - timeold;
        //printf("%d  ", timepass);
        if(timepass < TICK_INTERVAL){
            //ideawu.net: SDL_Delay(TICK_INTERVAL - timepass);
        }
    }
 
    return 1;
}

使用命令: gcc filename.c -lSDL_image -lSDL 编译. 然后 ./a.out 运行, 确保当前目录下有一个名为 fish.png的文件.

Written by benegg at 2009-05-12 14:14:56 | tags: , , ,

Mar 23

网络程序和单机程序(指进程内)有很大的相同点. 进程内程序的函数调用, 编译器把参数的传递隐藏了, 参数被序列化到栈上. 但对于网络程序, 一般需要开发者处理参数的编码和解码, 从带字节数组解码出参数, 或者将参数编码进字节数组.

有很多协议被用来做参数的编码和解码, 但有一种位置相关的编码方式比较常见, 而且速度快. 比如带有指令的字节数组, [0-3]字节是一个整数, 表示指令的类型, [4-8]字节是每一个整数参数, 如此.

C语言中有处理这些参数传递的惯用法. 下面介绍其中一种.

为每一种指令定义一个结构体(struct), 并定义 encode 和 decode 两个函数, 用于序列化和反序列化参数列表. 这样, 程序大概会看起来这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// file: args.h
// 参数定义
 
struct a_args{
    ...
};
 
int encode_a_args(char *p, struct a_args* args);
int decode_a_args(char *p, struct a_args* args);
 
struct b_args;
...
 
// file: proc.c
// 指令处理过程
 
int proc_a(struct a_args* args);
int proc_b(struct b_args* args);
...
 
// file: main.c
// 程序入口
char *p;
while((p= read_cmd()) != NULL){
    int type = *((int*)p);
    switch(type){
        case TYPE_A:
            decode_a_args(...);
            proc_a(...);
            break;
        ...
    }
}

Written by benegg at 2009-03-23 19:51:24 | tags: ,