OpenGL(glut) 开发跳一跳实战

1. 找到素材

因为老师给的glut库只支持特定格式的3D模型,本来想用blender建模导入,尝试不行。所以就先在网上先找到(.off) 的棋子模型

2. 实现棋子的显示

  • 声明模型
1
Model3D  *chess_piece_model = NULL; // main character model: chess piece
  • 创建模型实例并加载资源
1
2
chess_piece_model = new Model3D();
chess_piece_model->load_3d_model("resources/chess_piece.off");
  • 绘制模型

    棋子颜色为黑色纯色,也可使用texture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void display_chess_piece_model()
{

glPushMatrix();

glTranslatef(0, 14, 0); // pour le positioner sur le terrain
glScalef(10, 10, 10);


glBegin(GL_TRIANGLES);
for (int i = 0; i < chess_piece_model->nb_triangles; i++) {
glColor3f(0.0f, 0.0f, 0.0f);

glVertex3f(chess_piece_model->points[chess_piece_model->faces[i].a].x, chess_piece_model->points[chess_piece_model->faces[i].a].y, chess_piece_model->points[chess_piece_model->faces[i].a].z);

glVertex3f(chess_piece_model->points[chess_piece_model->faces[i].b].x, chess_piece_model->points[chess_piece_model->faces[i].b].y, chess_piece_model->points[chess_piece_model->faces[i].b].z);

glVertex3f(chess_piece_model->points[chess_piece_model->faces[i].c].x, chess_piece_model->points[chess_piece_model->faces[i].c].y, chess_piece_model->points[chess_piece_model->faces[i].c].z);
}
glEnd();
glPopMatrix();
}

3. 实现平台的显示

平台是基于立方体做transform得到的。所以要先实现立方体的绘制。

绘制立方体,参见这篇文章

https://www.cnblogs.com/icmzn/p/5049768.html

用一个二维数组vertex_list记录立方体点位置

1
2
3
4
5
6
7
8
9
10
static const GLfloat vertex_list[][3] = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
};

image-20191104151452718

用另一个二维数组记录面和点的绘制顺序

1
2
3
4
5
6
7
8
static const GLint index_list[][4] = {
0, 2, 3, 1,
4, 6, 2, 0,
4, 0, 1, 5,
4, 6, 7, 5,
5, 7, 3, 1,
6, 2, 3, 7,
};

因为为了方便在平台不同面显示不同内容(方便打广告XD),把顶面和其他面的显示分开实现。

用了两个texture。一个是箭头放在顶面用来实现类似劲舞团的功能,另一个是纯色图片用于装饰其他面

以下是显示顶面的代码

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
void display_cube_face() {
glBindTexture(GL_TEXTURE_2D, texture_arrow->OpenGL_ID[0]);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

if (texture_arrow->isRGBA)
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA8, texture_arrow->img_color->lenx, texture_arrow->img_color->leny, GL_RGBA, GL_UNSIGNED_BYTE, texture_arrow->img_all);
else
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, texture_arrow->img_color->lenx, texture_arrow->img_color->leny, GL_RGB, GL_UNSIGNED_BYTE, texture_arrow->img_color->data);

glEnable(GL_TEXTURE_2D);

glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);

glBegin(GL_QUADS);
for (int j = 0; j < 4; ++j) {
switch (j)
{
case 0:
glTexCoord2f(0, 0);
break;
case 1:
glTexCoord2f(0, 1);
break;
case 2:
glTexCoord2f(1, 1);
case 3:
glTexCoord2f(1, 0);
break;
}
glVertex3fv(vertex_list[index_list[5][j]]);
}
glEnd();
glPolygonMode(GL_FRONT, GL_FILL); // front of a face is filled
glPolygonMode(GL_BACK, GL_LINE);
glDisable(GL_ALPHA_TEST);
glDisable(GL_TEXTURE_2D);

}

实现棋子移动

获取收入修改棋子位置

1
2
3
4
5
6
7
8
9
10
11
12
if (inp->keys[KEY_CODE_W]) {
chess_posZ += chees_move_speed;
}
if (inp->keys[KEY_CODE_S]) {
chess_posZ -= chees_move_speed;
}
if (inp->keys[KEY_CODE_A]) {
chess_posX += chees_move_speed;
}
if (inp->keys[KEY_CODE_D]) {
chess_posX -= chees_move_speed;
}

实现棋子跳跃

通过两个bool变量,jump和falldown来检测棋子跳起下落状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (jump) {
if (tim->global_timer_25_Hz)
{
if (!falldown) {
chess_posY += 0.6f;
}
else {
chess_posY -= 0.7f;
}

if (chess_posY > 20) falldown = true;
if (chess_posY < 5) {
chess_posY = 5;
jump = false;
falldown = false;
//debug("end jump");
}
}

}

实现类似劲舞团的输入响应

用一个二维数组记录每次正确输入后,棋子的新位置,即每个棋盘所在位置。

1
2
3
4
5
6
static const int chess_routes[][2] = {
0,20,
25,20,
50,20,
50,35,
};

用另一个二维数组记录,正确输入的键盘值序列。

1
2
3
4
5
6
static const int required_inputs[] = {
KEY_CODE_2,
KEY_CODE_8,
KEY_CODE_6,
KEY_CODE_4,
};

每一次按方向键,检测是否输入正确,并处理

1
2
3
4
5
6
7
8
if (inp->keys[KEY_CODE_UP]) {
if (required_inputs[chess_current_index] == KEY_CODE_8) {
chess_posX = chess_routes[chess_current_index][0];
chess_posZ = chess_routes[chess_current_index][1];
chess_current_index++;
//debug("%d\n", chess_current_index);
}
}

待解决问题

主要问题是我把相机视角设置为45度俯视。跟随棋子移动有问题。如果能正确锁定棋子,可以让平台随机生成,每到一个新的平台就自动生成下个平台,并确保显示正确。现在因为视角追随问题,还不能实现。

第二个问题是键盘输入。如果要实现跳一跳,要知道按了多久的空格键。有待解决。