当前位置:网站首页>用OpenGL绘制winXP版扫雷的笑脸表情
用OpenGL绘制winXP版扫雷的笑脸表情
2022-08-04 08:36:00 【zorchp】
tags: OpenGL Game
写在前面
最近看看OpenGL的东西, 学了一些基础的语法, 所以用来做点东西, 用基本的点线多边形等来绘制一个Windows XP中经典的游戏扫雷里面的标志性笑脸, 如下图:
思路
这个笑脸有四种形态,分别是初始状态的笑脸, 点击时候的o型嘴, 赢的时候的墨镜脸和输了时候的伤心脸, 下面通过简单的直线和圆来绘制, 都是简单图形, 本质上其实都是点的绘制, 这里我封装了一下函数, 调用会方便一些, 分别是通过vector<GLint>
表示的点, 这样用initializer_list
时候会方便很多.
其次就是一些小细节, 例如圆的绘制中的角度问题(这里就是嘴的绘制), 还有键鼠事件的交互, 我觉得熟悉了这个流程之后, 主要的思路就都放在点的坐标上了, 这里我建议可以通过Geogebra
这款软件进行草图的绘制, 找到待绘制的点的坐标之后会方便很多.
代码(C++)
下面是代码, 这里分成几个部分分别说:
首先是导言区, 导入相应的模块和常量.
#include <GL/glut.h>
#include <vector>
//#include <iostream>
#include <cmath>
using namespace std;
const int w = 400, h = 400;
const GLfloat pi = 3.1415926536f;
void init() {
glClearColor(1, 0, 1, 0);//黑色背景
glMatrixMode(GL_PROJECTION);//正投影
glLoadIdentity();
gluOrtho2D(-w, w, -h, h);
}
然后是一些自定义的函数, 分别是画圆画直线和画多边形(这里是四边形)的, 用起来比直接读取点要方便一些.
void drawCircle(GLint x, GLint y, GLint r,
vector<GLfloat> rgb = {
0, 0, 0},
GLint cir = 2, int mode = GL_POLYGON,
GLfloat lw = 1,
const int n = 10000) {
glColor3f(rgb[0], rgb[1], rgb[2]);
glLineWidth(lw);
glBegin(mode);
for (int i = 0; i < n; i++) {
glVertex2i(x + r * cos(cir * pi / n * i),
y + r * sin(cir * pi / n * i));
}
glEnd();
}
void drawLine(vector<GLint> p1, vector<GLint> p2, GLfloat lw = 1,
vector<GLfloat> rgb = {
0, 0, 0},//default:black
int mode = GL_LINE_STRIP) {
glColor3f(rgb[0], rgb[1], rgb[2]);
glLineWidth(lw);
glBegin(mode);
glVertex2i(p1[0], p1[1]);
glVertex2i(p2[0], p2[1]);
glEnd();
}
void drawPolygon(vector<GLint> p1, vector<GLint> p2,
vector<GLint> p3, vector<GLint> p4,
vector<GLfloat> rgb = {
0, 0, 0},//default:black
int mode = GL_POLYGON,
GLfloat lw = 1) {
glColor3f(rgb[0], rgb[1], rgb[2]);
glLineWidth(lw);
glBegin(mode);
glVertex2i(p1[0], p1[1]);
glVertex2i(p2[0], p2[1]);
glVertex2i(p3[0], p3[1]);
glVertex2i(p4[0], p4[1]);
glEnd();
}
最后就是主要的绘制了,
void display() {
// 绘制基本的笑脸
drawCircle(0, 0, 50, {
1, 1, 0});//face
drawCircle(-20, 15, 6);//left eye
drawCircle(20, 15, 6);//right eye
drawCircle(0, -10, 20, {
0, 0, 0}, -1, GL_LINE_STRIP, 3);//mouth
glFlush();
}
void openMouth() {
//点击时候的张嘴
drawCircle(-20, 15, 8);//left eye
drawCircle(20, 15, 8);//right eye
drawCircle(0, -10, 20, {
1, 1, 0}, -1, GL_LINE_STRIP, 3);//cover old mouth
drawCircle(0, -18, 10, {
0, 0, 0}, 2, GL_LINE_STRIP, 3);//mouth
glFlush();
}
void coolFace() {
//赢时候的墨镜表情
drawPolygon({
-40, 25}, {
-10, 25}, {
-10, 8}, {
-40, 8});//left eye
drawPolygon({
40, 25}, {
10, 25}, {
10, 8}, {
40, 8});//right eye
drawLine({
-10, 23}, {
10, 23}, 3);//glasses middle
drawLine({
-45, 20}, {
-40, 25}, 3);//glasses left
drawLine({
45, 20}, {
40, 25}, 3);//glasses right
glFlush();
}
void dieFace() {
//输了时候的伤心脸
drawCircle(0, 0, 50, {
1, 1, 0});//face
drawLine({
-12, 7}, {
-28, 23}, 3);
drawLine({
-12, 23}, {
-28, 7}, 3);//left eye
drawLine({
12, 7}, {
28, 23}, 3);
drawLine({
12, 23}, {
28, 7}, 3);//right eye
drawCircle(0, -10, 20, {
0, 0, 0}, 1, GL_LINE_STRIP, 3);//mouth
glFlush();
}
// 这里是键盘交互, 通过按下q或者esc键实现退出, 按d实现伤心脸, 按w实现墨镜脸
void Key(unsigned char key, int x, int y) {
switch (key) {
case 27:
case 'q':
exit(0);
case 'd':
dieFace();
break;
case 'w':
coolFace();
break;
}
}
// 鼠标事件, 点击笑脸变形为O型嘴
void Mouse(int btn, int state, int x, int y) {
// 如果在圆内, 点击生效
if (x * x + y * y - w * x - w * y + (w / 2) * w < 50 * 50) {
if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
// cout << x << " " << y << endl;
openMouth();
} else {
display();
}
}
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(200, 200);
glutInitWindowSize(w, h);
glutCreateWindow("MineSweeper Smiling Face");
init();
glutDisplayFunc(display);
glutKeyboardFunc(Key);
glutMouseFunc(Mouse);
glutMainLoop();
return 0;
}
最后实现结果:
顺便附带一下cmake文件:(我的测试环境是Mac, 在Windows中需要配置一下路径)
cmake_minimum_required(VERSION 3.21)
project(minesweeper-smile)
set(CMAKE_CXX_STANDARD 17)
set(program_SOURCES main.cpp)
link_directories("/opt/homebrew/lib")
include_directories("/opt/homebrew/include")
find_library(Cocoa_Library Cocoa)
find_library(OpenGl_Library OpenGL)
find_library(GLUT_Library glut)
add_executable(${
PROJECT_NAME} ${
program_SOURCES})
target_link_libraries(${
PROJECT_NAME}
${
Cocoa_Library}
${
OpenGl_Library}
${
GLUT_Library}
)
边栏推荐
猜你喜欢
随机推荐
关于常用状态码4XX提示错误
高等代数_证明_对称矩阵属于不同特征值的特征向量正交
【论文笔记】Understanding Long Programming Languages with Structure-Aware Sparse Attention
关于Oracle RAC 11g重建磁盘组的问题
虚拟机没有USB网卡选项怎么解决
【虚幻引擎UE】UE5基于Gltf加载插件实现gltf格式骨骼动画在线/本地导入和切换
【JS 逆向百例】某网站加速乐 Cookie 混淆逆向详解
GBase 8c中怎么查询数据库配置参数,例如datestyle。使用什么函数或者语法呢?
spark算子讲解
安装GBase 8c数据库集群时,报错误码:80000306,显示Dcs cluster not healthy。怎么处理错误呢?
powershell和cmd对比
从零开始C语言精讲篇6:结构体
金仓数据库KingbaseES客户端编程接口指南-JDBC(10. JDBC 读写分离最佳实践)
金仓数据库KingbaseES客户端编程接口指南-JDBC(9. JDBC 读写分离)
form表单提交到数据库储存
【JS 逆向百例】某网站加速乐 Cookie 混淆逆向详解
高等代数_证明_幂等矩阵一定能够相似对角化
研究性学习专题 3_LL(1)语法分析设计原理与实现
金仓数据库KingbaseES客户端编程接口指南-JDBC(5. JDBC 查询结果集处理)
dalle:zero-shot text-to-image generation