从OO语言到C语言,如何避免循环依赖?

标签 c entity game-engine circular-dependency

当我在下面说“实体”时,我并不是专门指与 ECS 模式相关的任何东西,我只是指一般的游戏实体。

在使用 TypeScript 完成之前的游戏开发之后,我正在尝试使用 C 语言进行游戏开发。我正在寻找一种 C 惯用方法来重用我熟悉的模式:每次勾选,游戏都会迭代实体列表,告诉每个实体更新自身,然后绘制自身。每个实体都知道如何更新自身,但需要有关整个游戏的信息才能进行更新。

// Game.ts
import Entity from './Entity.js'
class Game {
  entities: List<Entity>;

  tick(dt: number) {
    entities.forEach(e => e.tick(dt));
    entities.forEach(e => e.draw());
  }
}

// Entity.ts
import Game from './Game.ts'
class Entity {
  game: Game;

  constructor(g: Game) {
    this.game = g;
  }

  tick(dt: number) {
    this.move(dt);
    this.collide(this.game);
  }
  draw() { /* snip */}
}

在 C 中,我想要一个大的 Game 结构,其中包含所有实体的列表,并且每个实体都包含一个用于如何更新自身的函数指针。

// game.h
#include "entity.h"
typedef struct Game {
  Entity *entities;
} Game;

// entity.h
#include "game.h"
typedef struct Entity Entity;

typedef void (*tick) (Entity*);

struct Entity {
  Game *game;
  char* name;
  int x, y;
  tick* t;
};

然而,这需要对实体中的游戏和游戏中的实体进行循环引用,我认为这是不应该这样做的。我想到的唯一方法是在 game.h 中放置一个 tick_entity(Game *game, Entity *e) 函数,但是我的面向对象大脑想要进一步分离我的关注点,以避免让 Game 负责一切,特别是当我有不同类型的实体时。有没有更惯用的方法来完成我在这里想做的事情?

最佳答案

不要在 game.h#include "entity.h",反之亦然。只需向前声明您需要指向的内容即可。如果还没有的话,还可以添加 header 防护装置。

示例:

// game.h
#ifndef GAME_H                 // header guard
#define GAME_H

//#include "entity.h"          // remove this
typedef struct Entity Entity;  // forward declare

typedef struct Game {
    Entity* entities;
} Game;

#endif
// entity.h
#ifndef ENTITY_H               // header guard
#define ENTITY_H

//#include "game.h"            // remove this
typedef struct Game Game;      // forward declare
typedef struct Entity Entity;

typedef void (*tick)(Entity*);

struct Entity {
    Game* game;
    char* name;
    int x, y;
    tick* t;
};

#endif

关于从OO语言到C语言,如何避免循环依赖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71100649/

相关文章:

c++ - 在 C 和 C++ 中动态声明数组大小

C - 在函数中写入字符串。错误 :expected expression

ios - CoreData 获取实体

javascript - HTML5 游戏引擎 - JavaScript 动画

java - 你如何在没有教程的情况下学习框架

c++ - 无论如何将 VkDescriptorImageInfo 设置为 null 或有某种方式使用 VkWriteDescriptorSet 跳过而不提示 vulkan

c - 我如何知道调制解调器何时完成对 AT 命令的响应?

c - 如何检查 C 中首先计算哪个表达式?

java - 如果实体名称保存在变量中,如何编写 hibernate 插入查询

database - 字 "Must"或字 "Can"表示完全参与