移植2D物理引擎到LVGL

背景

在LVGL交流群,有网友提出想要移植物理引擎到LVGL,遂有了本文。阅读本文需要对IDF和LVGL有所了解
在这里插入图片描述

过程

2D物理引擎有很多,经过一番调研选择了Chipmunk2D

下载源码

此处省略一万字,Github访问可能会有些慢

添加文件

将源码中的src文件夹复制到,include/chipmunk/文件夹下,然后将chipmunk文件夹复制idf工程
在这里插入图片描述

完善lv_mem

lv_mem.h,lv_mem.c 文件里添加以下代码:

// lv_mem.h
void *lv_cp_malloc(size_t num,size_t size){
// lv_mem.c
void *lv_cp_malloc(size_t num,size_t size){
    size_t total_size = num * size;
    void* ptr = lv_malloc(total_size);  // 分配内存

    if (ptr != NULL) {
        lv_memset(ptr, 0, total_size);  // 初始化为零
    }

    return ptr;
}

配置Chipmunk2D

修改chipmunk.h,修改完成以后,物理引擎将共用LVGL的内存,总共8KB

// 添加头文件
#include "lvgl.h"
// 修改如下代码
#ifndef CP_BUFFER_BYTES
	#define CP_BUFFER_BYTES (8*1024) //默认32k,此处改为8k
#endif

#ifndef cpcalloc
	/// Chipmunk calloc() alias.
	// #define cpcalloc calloc
#define cpcalloc lv_cp_malloc
#endif

#ifndef cprealloc
	/// Chipmunk realloc() alias.
	// #define cprealloc realloc
	#define cprealloc lv_realloc
#endif

#ifndef cpfree
	/// Chipmunk free() alias.
	// #define cpfree free
	#define cpfree lv_free
#endif

编写Demo

新建 chipmunk_demo文件夹如下:
在这里插入图片描述
并在component.mk文件中添加配置路径:

COMPONENT_SRCDIRS := . \
                  chipmunk \
                  chipmunk_demo

编写代码:
1.创建一个世界
2. 给这个世界添加重力
3. 创建四面墙围成框
4. 小框里面创建一个小球
5. 给墙和小球分别设置摩擦系数和弹性系数
6. 给小球随机设置一个初始速度
7. 启动定时器,定时调用 cpSpaceStep(space, 1.0/30.0);来推动时间前进
8. 定时读取并跟新小球的位置

根据物理学原理:小球按照抛物线运动,碰撞到四周时会反弹

物理引擎模拟重力

各个文件代码如下

// chipmunk_demo.h
#ifndef CHIP_MUNK_ESP_DEMO_H
#define CHIP_MUNK_ESP_DEMO_H
#include "lvgl.h"
#include "esp_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "chipmunk/chipmunk.h"
#include "chipmunk/chipmunk_structs.h"


void start_chipmunk_esp_example();


#endif
//chipmunk_demo.c
#include "chipmunk_demo.h"

#include "lvgl.h"
#define WIDTH 480
#define HEIGHT 480
#define BALL_RADIUS 20
cpSpace *space;
cpBody *staticBody;
cpBody * ballBody;
lv_obj_t *ballObj;
const static double width = 480.0;
const static double height = 480.0;
void on_timer(lv_timer_t *t);


void start_chipmunk_esp_example(){

    lv_obj_t * bg = lv_obj_create(lv_scr_act());
    lv_obj_set_size(bg,width,height);
    lv_obj_center(bg);
    lv_obj_set_style_pad_all(bg,0,LV_PART_MAIN);
    lv_obj_set_style_bg_color(bg,lv_color_hex(0x000000),LV_PART_MAIN);
    ballObj = lv_obj_create(bg);

    lv_obj_remove_style_all(ballObj);
    // 生成一个随机颜色
    lv_color_t random_color = lv_color_make(rand() % 256, rand() % 256, rand() % 256);
    // 将随机颜色应用到对象上
    lv_obj_set_style_bg_color(ballObj, random_color, LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ballObj,LV_OPA_100,LV_PART_MAIN);
    lv_obj_set_style_radius(ballObj,LV_RADIUS_CIRCLE,LV_PART_MAIN);
    lv_obj_set_size( ballObj,BALL_RADIUS*2,BALL_RADIUS*2);

    lv_obj_set_pos(ballObj,0,0);


    // 创建物理空间
    space = cpSpaceNew();
    cpSpaceSetGravity(space, cpv(0, 100));

    // 创建静态物体,即边界
    staticBody = cpSpaceGetStaticBody(space);
    cpShape *shape = cpSegmentShapeNew(staticBody, cpv(0,0), cpv(0, HEIGHT), 0.0f);
    cpShapeSetFriction(shape, 1.0);
    cpShapeSetElasticity(shape, 1.0);
    cpSpaceAddShape(space, shape);
    shape = cpSegmentShapeNew(staticBody, cpv(0, HEIGHT), cpv(WIDTH, HEIGHT), 0.0f);
    cpShapeSetFriction(shape, 1.0);
    cpShapeSetElasticity(shape, 1.0);
    cpSpaceAddShape(space, shape);
    shape = cpSegmentShapeNew(staticBody, cpv(WIDTH, HEIGHT), cpv(WIDTH, 0), 0.0f);
    // cpShapeSetFriction(shape, 1.0);
    cpShapeSetElasticity(shape, 1.0);
    cpSpaceAddShape(space, shape);
    shape = cpSegmentShapeNew(staticBody, cpv(WIDTH, 0), cpv(0, 0), 0.0f);
    cpShapeSetFriction(shape, 1.0);
    cpShapeSetElasticity(shape, 1.0);
    cpSpaceAddShape(space, shape);

    // // 创建1个小球
    cpFloat radius = 20.0;
    cpFloat x = cpflerp(radius * 2, WIDTH - radius * 2, (cpFloat)rand() / (cpFloat)RAND_MAX);
    cpFloat y = cpflerp(radius * 2, HEIGHT - radius * 2, (cpFloat)rand() / (cpFloat)RAND_MAX);

    ballBody = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 0.0f, radius, cpvzero)));
    cpBodySetPosition(ballBody, cpv(x, y));
    cpShape *ball_shape = cpSpaceAddShape(space, cpCircleShapeNew(ballBody, radius, cpvzero));
    cpShapeSetFriction(ball_shape, 0.7);
    cpShapeSetElasticity(ball_shape, 0.8);
    cpVect velocity = cpv((cpFloat)rand() / (cpFloat)RAND_MAX * 200 - 100, (cpFloat)rand() / (cpFloat)RAND_MAX * 200 - 100);
    cpBodySetVelocity(ballBody, velocity);



    lv_timer_t *timer = lv_timer_create(on_timer,30,NULL);
    lv_timer_set_repeat_count(timer,-1);

}
void on_timer(lv_timer_t *t){
    cpSpaceStep(space, 1.0/30.0);

    printf("Ball Position: (%.2f, %.2f)\n", cpBodyGetPosition(ballBody).x, cpBodyGetPosition(ballBody).y);
    lv_obj_set_pos(ballObj, cpBodyGetPosition(ballBody).x-20, cpBodyGetPosition(ballBody).y-20);
}


  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值