C语言学习记录20240622

news2024/11/26 16:26:44

这次需要用 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() {
    // 初始化 Allegro
    if (!al_init()) {
        fprintf(stderr, "Failed to initialize Allegro!\n");
        return -1;
    }

    // 安装键盘驱动,安装成功或已经安装过则返回 true
    if (!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)->heading
	        draw_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_H

extern 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.coloradmin.cn/o/1849008.html

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

相关文章

打破数据分析壁垒:SPSS复习必备(五)

一、分类变量的统计描述与参数估计 1、分类变量的统计描述指标体系 1&#xff09;频数分布情况描述 各个类别的样本数和所占比例分别称为频数&#xff08;绝对频数&#xff09;和百分比&#xff08;构成比&#xff09;。 累计频数是指本类别及较低类别出现的次数之和&#…

小熊文件工具箱免费版

小熊文件工具箱是一款基于本地离线操作的一系列工具的合集&#xff0c;最大特点是各种批量任务的执行&#xff0c;包含了智能证件照&#xff0c;自动抠图&#xff0c;直播录制&#xff0c;九宫格切图&#xff0c;拼图&#xff0c;视频格式转换及压缩&#xff0c;zip压缩解压缩&…

学习es6

1、let变量 2、const常量 3、解构赋值 4、模板字符串 5、简化对象写法 6、参数默认值 7、rest参数 8、扩展运算符 9、扩展对象方法 10、扩展数组方法 11、Set 12&#xff0c;Promise 13、Module模块

Android | 性能优化 之 TraceView工具的使用

上代码&#xff01; 先加权限&#xff1a; <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name"android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 选择跟踪范围,在开始追踪和结束…

sdlan如何智能组网?

【天联】组网是一款异地组网内网穿透产品&#xff0c;由北京金万维科技有限公司自主研发&#xff0c;旨在解决不同地区电脑与电脑、设备与设备、电脑与设备之间的信息远程通信问题。【天联】的操作简单、跨平台应用、无网络要求以及独创的安全加速方案等特点&#xff0c;使得它…

MyBatis系列六: 映射关系多对一

动态SQL语句-更复杂的查询业务需求 官方文档基本介绍映射方式配置Mapper.xml的方式-应用实例注解的方式实现-应用实例课后练习 官方文档 文档地址: https://mybatis.org/mybatis-3/zh_CN/sqlmap-xml.html 基本介绍 ●基本介绍 1.项目中多对1的关系是一个基本的映射关系, 也可…

镜像操作_容器操作_镜像拉取_镜像开机启动_镜像删除等常用操作---分布式云原生部署架构搭建008

docker的常用命令大全啊 然后再来看容器的常用命令,快速过一遍 找镜像在这里 hub.docker.com 这里 去找到对应的 镜像 直接docker pull 就可以了 然后注意这里有个tags,就是标签,镜像的标签 其实就是各个版本

CTFHUB-SSRF-POST请求

通过file协议访问flag.php文件内容 ?urlfile:///var/www/html/flag.php 右键查看页面源代码 需要从内部携带key发送post数据包即可获得flag ?urlhttp://127.0.0.1/flag.php 得到了key 构造POST请求数据包&#xff0c;进行url编码&#xff08;新建一个txt文件&#xff0c;…

vue3自动导入---组件库elements-ui,vuetify以及scss样式的自动导入

自动导入 我们在使用第三方组件库和css样式文件时&#xff0c;都需要进行引入&#xff0c;可以在单个组件内单独引用&#xff0c;也可以在全局引入或一次引入所有组件&#xff1b;但是&#xff0c;一般情况下我们都不会全部引入&#xff0c;这会是打包的结果变大&#xff0c;而…

TCP 和 UDP 可以同时绑定相同的端口吗?

在网络编程中&#xff0c;TCP和UDP都可以绑定到同一个端口上进行通信。TCP和UDP是OSI模型中的传输层协议&#xff0c;它们分别使用不同的端口号来区分不同的应用程序或服务。 TCP&#xff08;Transmission Control Protocol&#xff09;提供了面向连接的、可靠的传输服务&…

【Mac】FxFactory 8 Pro for Mac(视觉特效处理包)及同类型软件介绍

软件介绍 FxFactory Pro 是一款功能强大的插件管理和创作工具&#xff0c;专为视频编辑器和特效艺术家设计&#xff0c;适用于 macOS 系统。它集成了大量的视频特效插件&#xff0c;并与多种主流视频编辑软件无缝兼容&#xff0c;如 Final Cut Pro、Premiere Pro、After Effec…

Unity 限时免费资源 - FANTASTIC万圣节资源包

Unity 资源 - FANTASTIC - Halloween Pack 万圣节包 前言资源包内容领取兑换码 前言 亲爱的 Unity 游戏开发者们&#xff0c;今天要给大家介绍一款限时免费的优质资源包 - FANTASTIC - Halloween Pack 万圣节资源包。 这个资源包为您的游戏创作带来了丰富的万圣节主题元素。其…

PCB行业迈入数字化新时代,智能工厂引领未来制造

在传统的PCB生产过程中&#xff0c;人工操作、纸质记录、经验判断等方式占据了主导地位。然而&#xff0c;这种方式不仅效率低下&#xff0c;而且容易出现误差&#xff0c;导致产品质量不稳定。同时&#xff0c;随着市场竞争的加剧&#xff0c;客户对产品的交期、质量、成本等方…

什么是局域网IP?

局域网IP&#xff08;Local Area Network IP&#xff09;指的是在局域网内使用的IP地址。局域网是指在某个地理区域内&#xff0c;由一组相互连接的计算机组成的小型网络&#xff0c;常见于家庭、学校、办公室等场所。局域网IP可以用来实现内网穿透&#xff0c;即在复杂的网络环…

八-工具包3-pandas数据清洗及相关性

数据清洗概述 数据清洗是对一些没有用的、不合理的数据进行处理的过程。 很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况&#xff0c;如果要使数据分析更加准确&#xff0c;就需要对这些没有用的数据进行处理。 样本数据&#xff1a; from io import Str…

新零售解决方案:线上线下融合,驱动现代商业新浪潮-亿发

在数字化和智能化的商业环境中&#xff0c;新零售正在迅速改变传统的商业模式。作为新时代的零售解决方案&#xff0c;新零售通过线上线下深度结合&#xff0c;为企业提供了更灵活、高效的运营方式。本文将探讨新零售的四大特征&#xff0c;并详细描述其在中小企业中的应用&…

MySQL的DML语句

文章目录 ☃️概述☃️DML☃️添加数据☃️更新和删除数据☃️DML的重要性 ☃️概述 MySQL 通用语法分类 ● DDL: 数据定义语言&#xff0c;用来 定义数据库对象&#xff08;数据库、表、字段&#xff09; ● DML: 数据操作语言&#xff0c;用来对数据库表中的数据进行增删改 …

深入解析Transformer架构:大模型核心技术揭秘

在大模型发展历程中&#xff0c;有两个比较重要点&#xff1a;第一&#xff0c;Transformer 架构。它是模型的底座&#xff0c;但 Transformer 不等于大模型&#xff0c;但大模型的架构可以基于 Transformer&#xff1b;第二&#xff0c;GPT。严格意义上讲&#xff0c;GPT 可能…

MySQL数据备份操作步骤

常见的数据备份命令 备份命令备份速度恢复速度介绍功能适用场景lvm2快照快快一般、支持几乎热备、速度快一般中小型数据量的备份cp快快物理备份、灵活性低很弱少量数据备份xtrabackup较快较快实现innodb热备、对存储引擎有要求强大较大规模的备份mysqldump慢慢逻辑备份、适用所…

易管理工厂设备日志采集工具

免费试用下载: Gitee下载 最新版本 优势: A. 开箱即用. 解压直接运行.不需额外安装. B. 批管理设备. 设备配置均在后台管理. C. 无人值守 客户端自启动,自更新. D. 稳定安全. 架构简单,内存占用小,通过授权访问.