当我在下面说“实体”时,我并不是专门指与 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/