英文:
How to render multiple instances of the same struct in SDL2
问题
// 主游戏循环
void Game::gameLoop(){
实体 player;
实体 bulletHead;
实体 *bulletTail = new 实体();
bulletTail = &bulletHead;
player.x = 500;
player.y = 640;
player.dx = 0;
player.dy = 0;
player.texture = loadTexture((char*)"res/images/player.png");
SDL_QueryTexture(player.texture, NULL, NULL, &player.w, &player.h);
SDL_Texture *bulletTexture = loadTexture((char*)"res/images/bullet.png");
while(gameState != GameState::EXIT){
准备场景(); // 设置渲染
处理事件(); // 收集和处理用户输入
player.x += player.dx;
player.y += player.dy;
// 玩家按键输入
if(player.reload > 0) player.reload--;
if (up)
{
player.y -= 4;
}
if (down)
{
player.y += 4;
}
if (left)
{
player.x -= 4;
}
if (right)
{
player.x += 4;
}
// 允许每8帧射击子弹
if(fire && player.reload == 0){
player.reload = 8;
// 创建子弹
实体 *bullet = new 实体();
memset(bullet, 0, sizeof(实体));
bulletTail->next = bullet;
bulletTail = bullet;
bullet->x = player.x + 8;
bullet->y = player.y;
bullet->dx = 0;
bullet->dy = -PLAYER_BULLET_SPEED;
bullet->health = 1;
bullet->texture = bulletTexture;
SDL_QueryTexture(bullet->texture, NULL, NULL, &bullet->w, &bullet->h);
}
// 处理每颗子弹的物理和渲染
实体 *b = new 实体();
实体 *prev = new 实体();
prev = &bulletHead;
// 错误从这里开始 👇 🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫
for (b = bulletHead.next ; b != NULL ; b = b->next){
b->x += b->dx;
b->y += b->dy;
blit(b->texture, b->x, b->y);
if(b->y < 0){
if (b == bulletTail)
{
bulletTail = prev;
}
prev->next = b->next;
free(b);
b = prev;
}
prev = b;
}
// 错误在这里结束 🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫
blit(player.texture, player.x, player.y); // 显示图像
显示场景(); // 显示场景
SDL_Delay(16); // 限制帧速率为大约62帧每秒
}
SDL_DestroyWindow(window);
SDL_Quit();
}
英文:
I am building a C++ game using SDL2. Everything was going well and I was able to make the player shoot a single bullet. I later modified my code to render multiple bullets as shown below.
Main game loop
void Game::gameLoop(){
Entity player;
Entity bulletHead;
Entity *bulletTail = new Entity();
bulletTail = &bulletHead;
player.x = 500;
player.y = 640;
player.dx = 0;
player.dy = 0;
player.texture = loadTexture((char*)"res/images/player.png");
SDL_QueryTexture(player.texture, NULL, NULL, &player.w, &player.h);
SDL_Texture *bulletTexture = loadTexture((char*)"res/images/bullet.png");
while(gameState != GameState::EXIT){
prepareScene(); // sets up rendering
handleEvents(); // collects and precesses user input
player.x += player.dx;
player.y += player.dy;
// Player key input
if(player.reload > 0) player.reload--;
if (up)
{
player.y -= 4;
}
if (down)
{
player.y += 4;
}
if (left)
{
player.x -= 4;
}
if (right)
{
player.x += 4;
}
// allow fire bullet every 8 frames
if(fire && player.reload == 0){
player.reload = 8;
// Create bullet
Entity *bullet = new Entity();
memset(bullet, 0, sizeof(Entity));
bulletTail->next = bullet;
bulletTail = bullet;
bullet->x = player.x + 8;
bullet->y = player.y;
bullet->dx = 0;
bullet->dy = -PLAYER_BULLET_SPEED;
bullet->health = 1;
bullet->texture = bulletTexture;
SDL_QueryTexture(bullet->texture, NULL, NULL, &bullet->w, &bullet->h);
}
// handle physics and render for each bullet
Entity *b = new Entity();
Entity *prev = new Entity();
prev = &bulletHead;
// Error starts here 👇 🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫
for (b = bulletHead.next ; b != NULL ; b = b->next){
b->x += b->dx;
b->y += b->dy;
blit(b->texture, b->x, b->y);
if(b->y < 0){
if (b == bulletTail)
{
bulletTail = prev;
}
prev->next = b->next;
free(b);
b = prev;
}
prev = b;
}
// Error stops here 🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫🚫
blit(player.texture, player.x, player.y); // display image
presentScene(); // displays scene
SDL_Delay(16); // limits fps to around 62fps
}
SDL_DestroyWindow(window);
SDL_Quit();
}
As can be seen above, I can successfully create bullets but whenever I include the for loop to go through my linked list of bullets and move/draw them, the program closes unexpectedly. No error is shown, it just closes as soon as I ran it. Removing the for loop works but I need a way to loop through the linked list of bullets and draw/animate them.
答案1
得分: 0
标准库提供了许多容器供您使用,例如 std::vector
。以下示例假设您有一个 std::vector<Entity> bullets
。
如果您想遍历一个向量并在遍历过程中删除项目的选项,有两种选择,您可以使用 erase
方法,它会从向量中删除一个项目并返回一个新迭代器。
使用方法:
for (auto it = bullets.begin(); it != bullets.end(); /* 无操作,见下文 */) {
// 使用 *it 进行操作
if (/* 需要删除子弹 */) {
it = bullets.erase(it);
} else {
// 前进到下一个项目
it++;
}
}
英文:
The standard library has lots of containers for you to use, for example std::vector
. The examples below assume you have a std::vector<Entity> bullets
.
If you want to walk a vector and have the option to remove items as you go, there are two options, you can use the erase
method, which removes an item from the vector and returns a new iterator.
To use:
for (auto it = bullets.begin(); it != bullets.end(); /* no-op, see below */) {
// do stuff with *it
if (/* bullet needs to be removed */) {
it = bullets.erase(it);
} else {
// advance to the next item
it++;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论