从 OO 语言到 C,如何避免循环依赖?
Coming from OO languages to C, how can I avoid circular dependencies?
当我在下面说“实体”时,我并不是特指任何与 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)
函数,但我的 OO 大脑想要更多地分离我的关注点以避免让 Game
负责一切,尤其是当我有不同种类的实体时。有没有更惯用的方法来做我在这里想做的事情?
不要从 game.h
#include "entity.h"
,反之亦然。只需向前声明您需要指向的指针。如果您还没有添加头部保护,也可以添加。
示例:
// 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
当我在下面说“实体”时,我并不是特指任何与 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)
函数,但我的 OO 大脑想要更多地分离我的关注点以避免让 Game
负责一切,尤其是当我有不同种类的实体时。有没有更惯用的方法来做我在这里想做的事情?
不要从 game.h
#include "entity.h"
,反之亦然。只需向前声明您需要指向的指针。如果您还没有添加头部保护,也可以添加。
示例:
// 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