C语言学习记录20240622

这次需要用 C 语言库 Allegro 写爆破彗星游戏。项目有一些描述如需要绘制飞船、彗星、子弹,需要响应按键实现飞船加速、减速、转向、开火,需要绘制弹道,需要实现彗星旋转、缩放,需要碰撞检测,需要显示计分。

这些用 wxPython 不难实现,因为有面向对象能帮我们很好地组织代码,甚至能在写代码前先画好类图。但在 C 语言里,没有类实现,难道靠注释约定函数们谁跟谁负责什么功能。

模糊的印象,类是用来描述具有相同属性和方法的一组事物的数据结构。在 Python 中,没有属性,可以只是函数;没有方法,可以是命名元组或字典;有存储变量和一个函数,可以是闭包。
没有属性可以是类吗?好像也行,比如写个通用的工具类,里面放一些常用的日志、计算之类的只和类绑定的静态方法。
没有方法可以是类吗?也可以,避免使用全局变量,写一个类专门存放只与类绑定的全局变量,然后通过类来调用。
闭包是类吗?它不能继承,也不能重写闭包里的函数。
最后似乎可以通过这些简单逻辑粗略得出结论,类是封装、继承、多态这三个面向对象概念的具体实现。

C 语言虽然没有直接的类实现,但可以通过结构体封装属性变量和方法,结构体也能通过嵌套实现继承效果,至于多态,指针是不是更自由。

这里 C 语言实现封装,我见过的一种是结构体中的方法用函数指针表示,还有一种是结构体模拟类只负责保存属性,方法函数单独写,但函数必须有一个参数是指向模拟类结构体变量的指针。

再看《嗨翻C语言》第 535 页的void draw_ship(Spaceship* s),应该是第二种方法,这样的话先按这种方式写出飞船类。

对引用和指针也很困惑,直接查看《引用与指针的区别》https://blog.csdn.net/HUAERBUSHI521/article/details/118368696

在其他模块中调用全局变量,需要使用 extern 声明,表明是调用外部变量。

多个模块怎么避免重复包含头文件?在头文件中使用预处理#ifndef #define #end,通过判断是否定义指定变量来跳过其他代码,有点像 Python 中判断if __name__ == "__main__"

进展缓慢,只写了飞船的显示部分,写的时候查漏补缺挺好。

C语言学习记录20240622
main.c

#include <stdio.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include "./utility.h"
#include "./spaceship.h"// 全局变量 
const int WIDTH = 800; // 屏幕尺寸 
const int HEIGHT = 600;
const int FPS = 60; // 帧率 
ALLEGRO_FONT *font_40; // 字体 int main() {// 初始化 Allegroif (!al_init()) {fprintf(stderr, "Failed to initialize Allegro!\n");return -1;}// 安装键盘驱动,安装成功或已经安装过则返回 trueif (!al_install_keyboard()) {fprintf(stderr, "Failed to initialize keyboard!\n");return -1;}// 初始化图形绘制插件 if (!al_init_primitives_addon()) {fprintf(stderr, "Failed to initialize primitives addon!\n");return -1;}// 初始化字体插件 if (!al_init_font_addon()) {fprintf(stderr, "Failed to initialize font addon!\n");return -1;}// 初始化 TTF 字体插件 if (!al_init_ttf_addon()) {fprintf(stderr, "Failed to initialize ttf font addon!\n");return -1;}// 加载 TTF 字体,字号 40 font_40 = al_load_ttf_font("arial.ttf", 40, 0);// 启用多重采样al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);al_set_new_display_option(ALLEGRO_SAMPLES, 4, ALLEGRO_SUGGEST);// 创建指定宽高的窗口 ALLEGRO_DISPLAY *display = al_create_display(WIDTH, HEIGHT);if (!display) {fprintf(stderr, "Failed to create display!\n");return -1;}// 创建事件队列 ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue();if (!event_queue) {fprintf(stderr, "Failed to create event queue!\n");al_destroy_display(display);return -1;}// 创建定时器,每 1.0 / FPS 秒触发一次 ALLEGRO_TIMER *timer = al_create_timer(1.0 / FPS);// 注册事件源到事件队列 al_register_event_source(event_queue, al_get_display_event_source(display));al_register_event_source(event_queue, al_get_keyboard_event_source());al_register_event_source(event_queue, al_get_timer_event_source(timer));// 清除屏幕并填充黑色 al_clear_to_color(al_map_rgb(0, 0, 0));// 绘制背景 logo draw_logo();// 初始化并绘制飞船 Spaceship s = {WIDTH / 2.0, HEIGHT / 2.0, 0.0, 3.0, 0, al_map_rgb(0, 255, 0)};draw_ship(&s);// 交换缓冲区al_flip_display();// 启动定时器 al_start_timer(timer);// 轮询事件 bool done = false;while (!done) {ALLEGRO_EVENT event;// 等待从事件队列取出事件 al_wait_for_event(event_queue, &event);// 处理按键事件,这里响应 ESC 按键 if (event.type == ALLEGRO_EVENT_KEY_DOWN && event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {done = true;}// 处理窗口事件,这里响应点击窗口右上角关闭 if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {done = true;}// 处理定时器事件 if (event.type == ALLEGRO_EVENT_TIMER) {// 清屏并更新绘制al_clear_to_color(al_map_rgb(0, 0, 0));draw_logo();// 每次更新转动 5 度 s.heading += 5.0; // s.heading 相当于 (&s)->headingdraw_ship(&s);al_flip_display();} }// 销毁资源,释放内存 al_destroy_timer(timer);al_destroy_font(font_40);al_destroy_display(display);al_destroy_event_queue(event_queue);return 0;
}

spaceship.h

#ifndef _SPACESHIP_H
#define _SPACESHIP_H#include <allegro5/allegro.h>typedef struct {float sx; // 飞船中屏幕中的坐标 float sy;float heading; //飞船朝向角度,如 30 度为 30.0 float speed;int gone; // 是否阵亡ALLEGRO_COLOR color; 
} Spaceship;void draw_ship(Spaceship*);#endif

spaceship.c

#include <allegro5/allegro_primitives.h>
#include "./spaceship.h"
#define DEGREES(x) ((x) * ALLEGRO_PI / 180.0)// 绘制飞船
void draw_ship(Spaceship* s) {ALLEGRO_TRANSFORM transform;al_identity_transform(&transform);al_rotate_transform(&transform, DEGREES(s->heading));al_translate_transform(&transform, s->sx, s->sy);al_use_transform(&transform);// 画线需要在调用 al_create_display 前设置多重采样以抗锯齿 al_draw_line(-8, 9, 0, -11, s->color, 3.0f);al_draw_line(0, -11, 8, 9, s->color, 3.0f);al_draw_line(-6, 4, -1, 4, s->color, 3.0f);al_draw_line(6, 4, 1, 4, s->color, 3.0f);// 重置变换矩阵,不然会影响其他绘制内容 al_identity_transform(&transform);al_use_transform(&transform);
}

utility.h

#ifndef _UTILITY_H
#define _UTILITY_Hextern const int WIDTH;
extern const int HEIGHT;
extern ALLEGRO_FONT *font_40;void draw_logo();#endif

utility.c

#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include "./utility.h"void draw_logo() {const char *text = "SmileBasic";// 获取指定字体的字符串外边框尺寸 int bbx, bby, bbw, bbh;al_get_text_dimensions(font_40, text, &bbx, &bby, &bbw, &bbh);// 居中绘制字符串,纵轴偏上显示 al_draw_text(font_40, al_map_rgb(255, 255, 255), WIDTH / 2.0, HEIGHT / 2.0 - bbh * 1.5, ALLEGRO_ALIGN_CENTRE, text);// 绘制红色矩形边框,四周设置边距 10 float padding = 10.0;float rect_x1 = (WIDTH - bbw) / 2.0 - padding;float rect_y1 = HEIGHT / 2.0 - bbh * 1.5 - padding;float rect_x2 = rect_x1 + bbw + padding * 2;float rect_y2 = rect_y1 + bbh * 1.5 + padding * 2;al_draw_rectangle(rect_x1, rect_y1, rect_x2, rect_y2, al_map_rgb(255, 0, 0), 2.0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32400.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis—SortedSet数据类型及其常用命令详解

文章目录 一、Redis概述SortedSet类型1 ZADD&#xff1a;向有序集合添加成员2 ZREM&#xff1a;从有序集合中移除一个或多个成员3 ZSCORE : 获取sorted set中的指定元素的score值4 ZRANK&#xff1a;获取sorted set 中的指定元素的排名5 ZCARD&#xff1a;获取sorted set中的元…

赵丽颖纯白茉莉绽放温柔之美

赵丽颖纯白茉莉&#xff0c;绽放温柔之美在这个繁忙喧嚣的娱乐圈&#xff0c;赵丽颖以其独特的魅力&#xff0c;成为了无数人心中的白月光。近日&#xff0c;赵丽颖工作室发布了一组live图&#xff0c;她身着一袭温柔白裙&#xff0c;宛如一朵盛开的纯白茉莉花&#xff0c;美得…

kali linux安装中文输入法

kali linux安装中文输入法&#xff1a;先进入root权限 第1步&#xff1a;安装fctix sudo apt-get install fcitx第2步&#xff1a;安装fcitx-pinyin输入法 apt-get install fcitx-pinyin第3步&#xff1a;配置输入法 打开 Fcitx配置 应用&#xff0c;点击 &#xff0c;去除勾…

音视频的Buffer处理

最近在做安卓下UVC的一个案子。正好之前搞过ST方案的开机广告&#xff0c;这个也是我少数最后没搞成功的项目。当时也有点客观原因&#xff0c;当时ST要退出机顶盒市场&#xff0c;所以一切的支持都停了&#xff0c;当时啃他家播放器几十万行的代码&#xff0c;而且几乎没有文档…

RIP动态路由配置

1、搭建网络 搭建拓扑、规划IP地址、划分网段、设置端口 2、配置交换机&#xff0c;路由器 三层交换机配置 Switch>enable Switch#conf t Enter configuration commands, one per line. End with CNTL/Z. Switch(config)#hostname S3560S3560(config)#vlan 10 S3560(con…

【Excel经验】字符串处理方法

概览-公式汇总 序号公式功能公式公式示例公式说明1把多列内容拼接在一起&#xff0c;作为新的一列的内容CONCATENATE (text1,text2,…)CONCATENATE(A2,“#”,B2,“”,C2)用于根据多个列的内容拼成我们指定格式的内容&#xff0c;拼接的内容通常来源于原始数据&#xff0c;同时…

深度学习论文: Depth Anything V2

深度学习论文: Depth Anything V2 Depth Anything V2 PDF: https://arxiv.org/pdf/2406.09414v1 代码:https://depth-anything-v2.github.io/ PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://github.com/shanglianlm0525/PyTorch-Networks …

51单片机定时器中断配置

测试环境 单片机型号&#xff1a;STC8G1K08-38I-TSSOP20&#xff0c;其他型号请自行测试&#xff1b; IDE&#xff1a;Keil C51&#xff1b; 定时器配置及主要代码 以定时器T0为例&#xff0c;查看手册&#xff0c;有4种工作模式&#xff1a;模式0&#xff08;16位自动重装载…

MSPM0G3507——GPIO例程讲解1——input_capture

函数&#xff1a; 参数&#xff1a; 返回值&#xff1a; 主函数代码&#xff1a; #include "ti_msp_dl_config.h"extern volatile uint32_t interruptVectors[];int main(void) {SYSCFG_DL_init(); //把所有的LED灯和按键初始化了一…

LangChain:如何高效管理 LLM 聊天历史记录?

LangChain 团队发布了一篇关于使用 Dragonfly DB 来有效管理 LangChain 应用程序聊天历史记录的教程。 该教程旨在解决用户在使用 LangChain 应用程序时普遍遇到的一个问题&#xff1a;如何高效地管理聊天历史记录。 LangChain 团队在推文中强调了 Dragonfly DB 在管理聊天历…

【vue3|第12期】Vue3的Props详解:组件通信

日期&#xff1a;2024年6月19日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

【Redis】黑马点评短信登录

https://blog.csdn.net/qq_33888850/article/details/129770077 https://blog.csdn.net/weixin_51515308/article/details/128010464 https://www.bilibili.com/video/BV1cr4y1671t?p24 导入数据库 https://github.com/MagicToDo/hm-dianping sql文件在 hm-dianping-init\src…

计算机网络:运输层 - TCP首部格式 连接的创建与释放

计算机网络&#xff1a;运输层 - TCP首部格式 & 连接的创建与释放 TCP首部格式源端口 目的端口序号确认号数据偏移保留控制位窗口检验和紧急指针 TCP连接创建 - 三次握手TCP传输过程TCP连接释放 - 四次挥手 TCP首部格式 TCP的首部如下&#xff1a; 首部的前20 byte是固定的…

【物联网】室内定位技术及定位方式简介

目录 一、概述 二、常用的室内定位技术 2.1 WIFI技术 2.2 UWB超宽带 2.3 蓝牙BLE 2.4 ZigBee技术 2.5 RFID技术 三、常用的室内定位方式 3.1 信号到达时间 3.2 信号到达时间差 3.3 信号到达角 3.4 接收信号强度 一、概述 GPS是目前应用最广泛的定位技术&#xff0…

一种基于稀疏学习的旋转机械故障诊断方法(MATLAB)

稀疏表示方法是一种利用最少原子在过完备字典上表示或逼近信号的方法&#xff0c;该方法具有信号表示的高分辨率、稀疏性、强抗干扰能力和自适应性等优点。稀疏表示聚焦于设计合适的稀疏表示字典和挖掘有用的稀疏先验信息&#xff0c;其核心思想是将故障特征信息近似表示为字典…

Linux下VSCode的安装和基本使用

应用场景&#xff1a;嵌入式开发。 基本只需要良好的编辑环境&#xff0c;能支持文件搜索和跳转&#xff0c;就挺OK的。 之所以要在Linux下安装&#xff0c;是因为在WIN11上安装后&#xff0c;搜索功能基本废了&#xff0c;咋弄都弄不好&#xff0c;又不方便重装win系统&#x…

LLM功能应用的测试艺术:策略与实践

在人工智能技术日新月异的今天,大规模语言模型(LLMs)凭借其强大的自然语言处理能力,正逐渐成为众多应用和服务的核心驱动力。从智能客服到创作辅助,从信息检索到个性化推荐,LLMs的广泛应用对测试策略提出了全新的挑战。本文旨在探讨针对拥有LLM功能的应用或软件,如何制定…

韩顺平0基础学java——第29天

p592-599 线程 用户线程和守护线程 1.用户线程:也叫工作线程&#xff0c;当线程的任务执行完或通知方式结束 2守护线程:一般是为工作线程服务的&#xff0c;当所有的用户线选束&#xff0c;守护线程自动结束 3.常见的守护线程:垃圾回收机制 当我们希望当main线程结束后&…

2.APP测试-安卓adb抓取日志

1.打开手机的开发者模式&#xff0c;打开USB调试 &#xff08;1&#xff09;小米手机打开开发者模式&#xff1a; 【设置】-【我的设备】-【全部参数信息】-快速多次点击【OS版本】-进入开发者模式 &#xff08;2&#xff09;连接手机和电脑&#xff0c;手机打开USB调试 【设置…

05 - matlab m_map地学绘图工具基础函数 - 设置比例尺指北针

05 - matlab m_map地学绘图工具基础函数 - 设置比例尺指北针 0. 引言1. 关于m_scale2. 关于m_ruler3. 关于m_northarrow4. 结语 0. 引言 本篇介绍下m_map中添加指北针(m_northarrow)、比例尺(m_ruler)和进行比例缩放(m_scale)的函数及其用法 。 1. 关于m_scale m_scale用于图件…