C语言游戏开发:Pygame、SDL、OpenGL深度解析

C语言游戏开发:Pygame、SDL、OpenGL深度解析

C语言游戏开发:Pygame、SDL、OpenGL深度解析

在这里插入图片描述

一、前言:为什么游戏开发是C语言开发的重要技能?

学习目标

  • 理解游戏开发的本质:编写程序实现游戏逻辑、图形渲染、用户交互
  • 明确游戏开发的重要性:支撑游戏产业的发展,成为游戏开发者的必备技能
  • 掌握本章学习重点:Pygame、SDL、OpenGL的开发方法、避坑指南、实战案例分析
  • 学会使用C语言开发游戏,实现游戏逻辑和用户交互

重点提示

💡 游戏开发是C语言开发的重要技能!随着游戏产业的发展,游戏开发的需求越来越大,C语言的高性能和可移植性使其在游戏开发中具有重要地位。


二、模块1:Pygame游戏开发基础

2.1 学习目标

  • 理解Pygame的本质:基于SDL的Python游戏库,简化游戏开发
  • 掌握Pygame的核心架构:窗口管理、事件处理、图形渲染、音频播放
  • 掌握Pygame的开发方法:使用Pygame库进行游戏开发
  • 掌握Pygame的避坑指南:避免窗口创建失败、避免图形渲染错误、避免事件处理错误
  • 避开Pygame使用的3大常见坑

2.2 Pygame的核心架构

窗口管理:创建和管理窗口
事件处理:处理键盘、鼠标、触摸等输入事件
图形渲染:使用Surface进行图形绘制
音频播放:播放音频文件

2.3 Pygame的开发方法

代码示例1:Pygame窗口创建

import pygame import sys # 初始化Pygame pygame.init()# 设置窗口大小和标题 screen_width =800 screen_height =600 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("Pygame窗口创建")# 设置背景颜色 background_color =(255,255,255)# 游戏循环 running =Truewhile running:# 事件处理for event in pygame.event.get():if event.type== pygame.QUIT: running =False# 填充背景颜色 screen.fill(background_color)# 更新显示 pygame.display.flip()# 退出Pygame pygame.quit() sys.exit()

代码示例2:Pygame绘制图形

import pygame import sys # 初始化Pygame pygame.init()# 设置窗口大小和标题 screen_width =800 screen_height =600 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("Pygame绘制图形")# 设置颜色 white =(255,255,255) red =(255,0,0) blue =(0,0,255) green =(0,255,0)# 游戏循环 running =Truewhile running:# 事件处理for event in pygame.event.get():if event.type== pygame.QUIT: running =False# 填充背景颜色 screen.fill(white)# 绘制矩形 rect = pygame.Rect(300,200,200,200) pygame.draw.rect(screen, red, rect)# 绘制圆形 pygame.draw.circle(screen, blue,(400,300),100)# 绘制线条 pygame.draw.line(screen, green,(100,100),(700,500),5)# 更新显示 pygame.display.flip()# 退出Pygame pygame.quit() sys.exit()

三、模块2:SDL游戏开发基础

3.1 学习目标

  • 理解SDL的本质:Simple DirectMedia Layer,跨平台图形、音频、输入库
  • 掌握SDL的核心架构:窗口管理、事件处理、图形渲染、音频播放
  • 掌握SDL的开发方法:使用SDL 2.0库进行游戏开发
  • 掌握SDL的避坑指南:避免窗口创建失败、避免图形渲染错误、避免事件处理错误
  • 避开SDL使用的3大常见坑

3.2 SDL的核心架构

窗口管理:创建和管理窗口
事件处理:处理键盘、鼠标、触摸等输入事件
图形渲染:使用渲染器绘制图形
音频播放:播放音频文件

3.3 SDL的开发方法

代码示例3:SDL窗口创建

#include<SDL.h>intmain(int argc,char*argv[]){ SDL_Window *window =NULL; SDL_Renderer *renderer =NULL;// 初始化SDLif(SDL_Init(SDL_INIT_VIDEO)<0){fprintf(stderr,"SDL初始化失败:%s\n",SDL_GetError());return0;}// 创建窗口 window =SDL_CreateWindow("SDL窗口", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,800,600, SDL_WINDOW_SHOWN );if(window ==NULL){fprintf(stderr,"窗口创建失败:%s\n",SDL_GetError());SDL_Quit();return0;}// 创建渲染器 renderer =SDL_CreateRenderer(window,-1, SDL_RENDERER_ACCELERATED);if(renderer ==NULL){fprintf(stderr,"渲染器创建失败:%s\n",SDL_GetError());SDL_DestroyWindow(window);SDL_Quit();return0;}// 设置渲染器颜色SDL_SetRenderDrawColor(renderer,255,255,255,255);SDL_RenderClear(renderer);SDL_RenderPresent(renderer);// 事件循环 SDL_Event event;int quit =0;while(!quit){while(SDL_PollEvent(&event)){if(event.type == SDL_QUIT){ quit =1;}}}// 清理资源SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return0;}

代码示例4:SDL绘制图形

#include<SDL.h>intmain(int argc,char*argv[]){ SDL_Window *window =NULL; SDL_Renderer *renderer =NULL;// 初始化SDLif(SDL_Init(SDL_INIT_VIDEO)<0){fprintf(stderr,"SDL初始化失败:%s\n",SDL_GetError());return0;}// 创建窗口 window =SDL_CreateWindow("SDL绘制图形", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,800,600, SDL_WINDOW_SHOWN );if(window ==NULL){fprintf(stderr,"窗口创建失败:%s\n",SDL_GetError());SDL_Quit();return0;}// 创建渲染器 renderer =SDL_CreateRenderer(window,-1, SDL_RENDERER_ACCELERATED);if(renderer ==NULL){fprintf(stderr,"渲染器创建失败:%s\n",SDL_GetError());SDL_DestroyWindow(window);SDL_Quit();return0;}// 绘制图形SDL_SetRenderDrawColor(renderer,255,255,255,255);SDL_RenderClear(renderer);// 绘制矩形 SDL_Rect rect ={300,200,200,200};SDL_SetRenderDrawColor(renderer,255,0,0,255);SDL_RenderFillRect(renderer,&rect);// 绘制圆形int x =400, y =300, r =100;SDL_SetRenderDrawColor(renderer,0,0,255,255);for(int i = x - r; i <= x + r; i++){for(int j = y - r; j <= y + r; j++){int dx = i - x;int dy = j - y;if(dx * dx + dy * dy <= r * r){SDL_RenderDrawPoint(renderer, i, j);}}}// 绘制线条SDL_SetRenderDrawColor(renderer,0,255,0,255);SDL_RenderDrawLine(renderer,100,100,700,500);SDL_RenderPresent(renderer);// 事件循环 SDL_Event event;int quit =0;while(!quit){while(SDL_PollEvent(&event)){if(event.type == SDL_QUIT){ quit =1;}}}// 清理资源SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return0;}

四、模块3:OpenGL游戏开发基础

4.1 学习目标

  • 理解OpenGL的本质:跨平台图形库,用于3D和2D图形渲染
  • 掌握OpenGL的核心架构:上下文管理、着色器、顶点缓冲、纹理
  • 掌握OpenGL的开发方法:使用OpenGL 3.3+核心模式进行游戏开发
  • 掌握OpenGL的避坑指南:避免上下文创建失败、避免着色器编译错误、避免渲染错误
  • 避开OpenGL使用的3大常见坑

4.2 OpenGL的核心架构

上下文管理:创建和管理OpenGL上下文
着色器:顶点着色器和片段着色器,负责图形渲染
顶点缓冲:存储顶点数据
纹理:存储图像数据

4.3 OpenGL的开发方法

代码示例5:OpenGL三角形绘制

#include<stdio.h>#include<stdlib.h>#include<GL/glew.h>#include<GLFW/glfw3.h>const GLchar *vertexSource ="#version 330 core\n""layout (location = 0) in vec3 position;\n""void main() {\n"" gl_Position = vec4(position, 1.0);\n""}\n";const GLchar *fragmentSource ="#version 330 core\n""out vec4 color;\n""void main() {\n"" color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""}\n";intmain(){// 初始化GLFWif(!glfwInit()){fprintf(stderr,"GLFW初始化失败!\n");return0;}// 配置GLFWglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建窗口 GLFWwindow* window =glfwCreateWindow(800,600,"OpenGL三角形绘制",NULL,NULL);if(window ==NULL){fprintf(stderr,"窗口创建失败!\n");glfwTerminate();return0;}glfwMakeContextCurrent(window);// 初始化GLEWif(glewInit()!= GLEW_OK){fprintf(stderr,"GLEW初始化失败!\n");glfwTerminate();return0;}// 设置视口int width, height;glfwGetFramebufferSize(window,&width,&height);glViewport(0,0, width, height);// 顶点数据 GLfloat vertices[]={-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f};// 创建顶点缓冲对象 GLuint VBO, VAO;glGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER,sizeof(vertices), vertices, GL_STATIC_DRAW);// 编译顶点着色器 GLuint vertexShader =glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSource,NULL);glCompileShader(vertexShader); GLint success; GLchar infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS,&success);if(!success){glGetShaderInfoLog(vertexShader,512,NULL, infoLog);fprintf(stderr,"顶点着色器编译失败:%s\n", infoLog);}// 编译片段着色器 GLuint fragmentShader =glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentSource,NULL);glCompileShader(fragmentShader);glGetShaderiv(fragmentShader, GL_COMPILE_STATUS,&success);if(!success){glGetShaderInfoLog(fragmentShader,512,NULL, infoLog);fprintf(stderr,"片段着色器编译失败:%s\n", infoLog);}// 链接着色器程序 GLuint shaderProgram =glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glGetProgramiv(shaderProgram, GL_LINK_STATUS,&success);if(!success){glGetProgramInfoLog(shaderProgram,512,NULL, infoLog);fprintf(stderr,"着色器程序链接失败:%s\n", infoLog);}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 配置顶点属性glVertexAttribPointer(0,3, GL_FLOAT, GL_FALSE,3*sizeof(GLfloat),(GLvoid*)0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER,0);glBindVertexArray(0);// 渲染循环while(!glfwWindowShouldClose(window)){glfwPollEvents();// 清除颜色缓冲glClearColor(0.2f,0.3f,0.3f,1.0f);glClear(GL_COLOR_BUFFER_BIT);// 使用着色器程序glUseProgram(shaderProgram);// 绑定顶点数组对象glBindVertexArray(VAO);// 绘制三角形glDrawArrays(GL_TRIANGLES,0,3);glBindVertexArray(0);// 交换缓冲glfwSwapBuffers(window);}// 清理资源glDeleteVertexArrays(1,&VAO);glDeleteBuffers(1,&VBO);glDeleteProgram(shaderProgram);// 终止GLFWglfwTerminate();return0;}

五、模块4:实战案例分析——使用SDL实现简单的游戏

5.1 学习目标

  • 掌握使用SDL实现简单的游戏:通过SDL库实现一个简单的贪吃蛇游戏
  • 学会使用SDL的窗口管理、渲染、事件处理功能
  • 避开实战案例使用的3大常见坑

5.2 使用SDL实现简单的游戏

代码示例6:贪吃蛇游戏

#include<SDL.h>#include<stdio.h>#include<stdlib.h>#include<time.h>#defineSCREEN_WIDTH800#defineSCREEN_HEIGHT600#defineGRID_SIZE20#defineGRID_WIDTH(SCREEN_WIDTH / GRID_SIZE)#defineGRID_HEIGHT(SCREEN_HEIGHT / GRID_SIZE)#defineINITIAL_SNAKE_LENGTH3#defineSNAKE_SPEED100typedefstruct{int x;int y;} Point;typedefstruct{ Point head; Point body[100];int length;int direction;// 0: up, 1: right, 2: down, 3: left} Snake;typedefstruct{ Point position;int active;} Food;voidinit_snake(Snake *snake){ snake->length = INITIAL_SNAKE_LENGTH; snake->direction =1;// right snake->head.x = GRID_WIDTH /2; snake->head.y = GRID_HEIGHT /2;for(int i =1; i < snake->length; i++){ snake->body[i -1].x = snake->head.x - i; snake->body[i -1].y = snake->head.y;}}voiddraw_snake(SDL_Renderer *renderer, Snake *snake){SDL_SetRenderDrawColor(renderer,0,255,0,255); SDL_Rect head_rect ={snake->head.x * GRID_SIZE, snake->head.y * GRID_SIZE, GRID_SIZE, GRID_SIZE};SDL_RenderFillRect(renderer,&head_rect);for(int i =0; i < snake->length -1; i++){ SDL_Rect body_rect ={snake->body[i].x * GRID_SIZE, snake->body[i].y * GRID_SIZE, GRID_SIZE, GRID_SIZE};SDL_RenderFillRect(renderer,&body_rect);}}voidupdate_snake(Snake *snake,int*game_over){for(int i = snake->length -2; i >=0; i--){ snake->body[i +1]= snake->body[i];} snake->body[0]= snake->head;switch(snake->direction){case0:// up snake->head.y--;break;case1:// right snake->head.x++;break;case2:// down snake->head.y++;break;case3:// left snake->head.x--;break;}if(snake->head.x <0|| snake->head.x >= GRID_WIDTH || snake->head.y <0|| snake->head.y >= GRID_HEIGHT){*game_over =1;}for(int i =0; i < snake->length -1; i++){if(snake->head.x == snake->body[i].x && snake->head.y == snake->body[i].y){*game_over =1;}}}voidgenerate_food(Food *food, Snake *snake){int valid_position =0;while(!valid_position){ food->position.x =rand()% GRID_WIDTH; food->position.y =rand()% GRID_HEIGHT; valid_position =1;if(food->position.x == snake->head.x && food->position.y == snake->head.y){ valid_position =0;}for(int i =0; i < snake->length -1; i++){if(food->position.x == snake->body[i].x && food->position.y == snake->body[i].y){ valid_position =0;}}} food->active =1;}voiddraw_food(SDL_Renderer *renderer, Food *food){if(food->active){SDL_SetRenderDrawColor(renderer,255,0,0,255); SDL_Rect rect ={food->position.x * GRID_SIZE, food->position.y * GRID_SIZE, GRID_SIZE, GRID_SIZE};SDL_RenderFillRect(renderer,&rect);}}voidcheck_collision(Snake *snake, Food *food){if(snake->head.x == food->position.x && snake->head.y == food->position.y){ snake->length++; food->active =0;generate_food(food, snake);}}intmain(int argc,char*argv[]){ SDL_Window *window =NULL; SDL_Renderer *renderer =NULL;if(SDL_Init(SDL_INIT_VIDEO)<0){fprintf(stderr,"SDL初始化失败:%s\n",SDL_GetError());return0;} window =SDL_CreateWindow("贪吃蛇游戏", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );if(window ==NULL){fprintf(stderr,"窗口创建失败:%s\n",SDL_GetError());SDL_Quit();return0;} renderer =SDL_CreateRenderer(window,-1, SDL_RENDERER_ACCELERATED);if(renderer ==NULL){fprintf(stderr,"渲染器创建失败:%s\n",SDL_GetError());SDL_DestroyWindow(window);SDL_Quit();return0;}srand(time(NULL)); Snake snake;init_snake(&snake); Food food; food.active =0;generate_food(&food,&snake);int game_over =0;int last_time =SDL_GetTicks();int frame_time =0; SDL_Event event;while(!game_over){int current_time =SDL_GetTicks();int delta_time = current_time - last_time; last_time = current_time; frame_time += delta_time;while(SDL_PollEvent(&event)){if(event.type == SDL_QUIT){ game_over =1;}elseif(event.type == SDL_KEYDOWN){switch(event.key.keysym.sym){case SDLK_UP:if(snake.direction !=2){ snake.direction =0;}break;case SDLK_RIGHT:if(snake.direction !=3){ snake.direction =1;}break;case SDLK_DOWN:if(snake.direction !=0){ snake.direction =2;}break;case SDLK_LEFT:if(snake.direction !=1){ snake.direction =3;}break;}}}if(frame_time >= SNAKE_SPEED){update_snake(&snake,&game_over);check_collision(&snake,&food); frame_time =0;}SDL_SetRenderDrawColor(renderer,0,0,0,255);SDL_RenderClear(renderer);draw_snake(renderer,&snake);draw_food(renderer,&food);SDL_RenderPresent(renderer);SDL_Delay(16);// 限制帧率在60FPS}SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return0;}

六、本章总结与课后练习

6.1 总结

Pygame游戏开发:基于SDL的Python游戏库,简化游戏开发
SDL游戏开发:跨平台图形、音频、输入库,适合游戏开发
OpenGL游戏开发:跨平台图形库,用于3D和2D图形渲染
实战案例分析:使用SDL实现简单的贪吃蛇游戏

6.2 课后练习

  1. 编写程序:使用Pygame创建窗口并绘制图形
  2. 编写程序:使用Pygame处理键盘和鼠标事件
  3. 编写程序:使用Pygame播放音频
  4. 编写程序:使用SDL创建窗口并绘制图形
  5. 编写程序:使用SDL处理键盘和鼠标事件
  6. 编写程序:使用SDL播放音频
  7. 编写程序:使用OpenGL绘制三角形
  8. 编写程序:使用OpenGL绘制矩形
  9. 编写程序:使用OpenGL加载并显示纹理
  10. 编写程序:使用SDL和OpenGL结合开发3D游戏

Read more

【算法】【优选算法】BFS 解决拓扑排序

【算法】【优选算法】BFS 解决拓扑排序

目录 * 一、拓扑排序 * 1.1 有向无环图(DAG图) * 1.2 AOV 网:顶点活动图 * 1.3 拓扑排序 * 1.4 实现拓扑排序 * 二、207. 课程表 * 三、210. 课程表 II * 四、LCR 114. ⽕星词典 一、拓扑排序 1.1 有向无环图(DAG图) 有向无环图:有向无环图:一个无回路的有向图,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。 1.2 AOV 网:顶点活动图 在有向无环图的基础上,用顶点来表示一个活动,用边来表示活动执行的先后顺序。 1.

By Ne0inhk
【LeetCode经典题解】:二叉树转字符串递归解法的核心逻辑与代码解剖

【LeetCode经典题解】:二叉树转字符串递归解法的核心逻辑与代码解剖

🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:Java.数据结构 【前言】 在二叉树的算法问题中,将二叉树结构转化为特定格式的字符串是经典的基础题型,这一问题不仅考察对二叉树遍历的理解,更考验对递归逻辑和边界条件的处理能力。本文将围绕 tree2str 问题展开,通过逐行拆解代码的方式,分析如何利用递归实现二叉树到字符串的转换,并解读其中关键的边界处理技巧,帮助读者深入理解递归在树形结构问题中的应用思路。 文章目录: * 一、根据二叉树创建字符串 * 二、思路分析 * 三、代码 * 1.代码分析 * 1.1 主方法`tree2str`: * 1.2 递归辅助方法`tree2strChild` * 2.代码展示 一、根据二叉树创建字符串 链接直达:根据二叉树创建字符串 二、思路分析 要求将二叉树按照“根节点(左子树)

By Ne0inhk
排序算法指南:归并排序(非递归)

排序算法指南:归并排序(非递归)

前言:              非递归实现归并排序,通常被称为 “自底向上”(Bottom-Up) 的归并排序,与递归版本(先将数组对半拆分直到只剩一个元素,再通过递归栈回溯合并)不同,非递归版本直接从最小的子数组(长度为1)开始,两两合并,然后长度翻倍(2, 4, 8 ...),直到合并完整个数组。                                                                 一、归并排序非递归的核心思路          递归算法转换为非递归实现主要有两种常见方法:          1.使用栈结构模拟递归过程          2.将递归逻辑改写为循环结构          1.1 栈模拟失效          如果仅通过栈结构模拟递归过程,我们只能够做到拆分数组,而不能做到合并数组。          假设我们要排序数组 arr = [8, 4, 5, 7],下标是 0 到 3。          初始状态:栈中有任务 [0, 3]。                   第一步:弹

By Ne0inhk

MediaPipe姿态估计算法详解:2D/3D关键点转换机制揭秘

MediaPipe姿态估计算法详解:2D/3D关键点转换机制揭秘 1. 技术背景与问题提出 随着计算机视觉技术的快速发展,人体姿态估计(Human Pose Estimation)已成为智能健身、动作捕捉、虚拟现实和人机交互等领域的核心技术之一。其核心目标是从单张RGB图像中定位人体关键关节的位置,并构建出可解析的骨架结构。 传统方法依赖于复杂的深度学习模型(如OpenPose、HRNet),往往需要GPU支持且推理延迟较高。而Google推出的 MediaPipe Pose 模型则另辟蹊径,采用轻量级架构设计,在保证高精度的同时实现了毫秒级CPU推理性能,极大降低了部署门槛。 然而,一个常被忽视但至关重要的问题是:MediaPipe是如何从2D图像中输出33个3D关键点的?这些“3D”点是否真正具备空间深度信息?它们又是如何反向投影回2D进行可视化的? 本文将深入剖析MediaPipe姿态估计算法的核心机制,重点揭秘其2D/3D关键点转换逻辑,帮助开发者理解其工作原理并合理应用于实际项目中。 2. MediaPipe Pose核心架构解析 2.1 整体流程概览 M

By Ne0inhk