mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-22 17:49:43 +01:00
Add level debugger screen
The level debugger is toggleable in playtesting mode by pressing Y. You can toggle whether or not the game is paused inside of the debugger by pressing TAB. The debugger screen allows you to see entity and block properties, and allows you to move them around.
This commit is contained in:
parent
3c4ed36418
commit
91f87fa126
6 changed files with 332 additions and 1 deletions
|
@ -84,6 +84,7 @@ set(VVV_SRC
|
|||
src/Input.cpp
|
||||
src/KeyPoll.cpp
|
||||
src/Labclass.cpp
|
||||
src/LevelDebugger.cpp
|
||||
src/Localization.cpp
|
||||
src/LocalizationMaint.cpp
|
||||
src/LocalizationStorage.cpp
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Font.h"
|
||||
#include "GlitchrunnerMode.h"
|
||||
#include "Graphics.h"
|
||||
#include "LevelDebugger.h"
|
||||
#include "Localization.h"
|
||||
#include "LocalizationStorage.h"
|
||||
#include "KeyPoll.h"
|
||||
|
@ -7491,7 +7492,7 @@ int Game::get_timestep(void)
|
|||
|
||||
bool Game::physics_frozen(void)
|
||||
{
|
||||
return roomname_translator::is_pausing();
|
||||
return roomname_translator::is_pausing() || level_debugger::is_pausing();
|
||||
}
|
||||
|
||||
bool Game::incompetitive(void)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Graphics.h"
|
||||
#include "GraphicsUtil.h"
|
||||
#include "KeyPoll.h"
|
||||
#include "LevelDebugger.h"
|
||||
#include "Localization.h"
|
||||
#include "LocalizationMaint.h"
|
||||
#include "LocalizationStorage.h"
|
||||
|
@ -2436,6 +2437,12 @@ void gameinput(void)
|
|||
}
|
||||
}
|
||||
|
||||
level_debugger::input();
|
||||
if (level_debugger::is_pausing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game.press_map = false;
|
||||
if (key.isDown(KEYBOARD_ENTER) || key.isDown(SDLK_KP_ENTER) || key.isDown(game.controllerButton_map) )
|
||||
{
|
||||
|
|
306
desktop_version/src/LevelDebugger.cpp
Normal file
306
desktop_version/src/LevelDebugger.cpp
Normal file
|
@ -0,0 +1,306 @@
|
|||
#include "LevelDebugger.h"
|
||||
|
||||
#include "Constants.h"
|
||||
#include "Entity.h"
|
||||
#include "Font.h"
|
||||
#include "Graphics.h"
|
||||
#include "KeyPoll.h"
|
||||
#include "Localization.h"
|
||||
#include "Map.h"
|
||||
#include "UtilityClass.h"
|
||||
#include "VFormat.h"
|
||||
|
||||
namespace level_debugger
|
||||
{
|
||||
bool active = false;
|
||||
bool should_pause = true;
|
||||
bool tab_held = false;
|
||||
bool debug_held = false;
|
||||
|
||||
// Moving entities/blocks
|
||||
bool mouse_held = false;
|
||||
int held_entity = -1;
|
||||
int held_block = -1;
|
||||
int grabber_offset_x = 0;
|
||||
int grabber_offset_y = 0;
|
||||
|
||||
bool is_pausing(void)
|
||||
{
|
||||
return active && should_pause;
|
||||
}
|
||||
|
||||
bool is_active(void)
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
void toggle_active(void)
|
||||
{
|
||||
active = !active;
|
||||
}
|
||||
|
||||
bool mouse_within(SDL_Rect* rect)
|
||||
{
|
||||
return key.mx >= rect->x && key.mx < rect->x + rect->w &&
|
||||
key.my >= rect->y && key.my < rect->y + rect->h;
|
||||
}
|
||||
|
||||
void input(void)
|
||||
{
|
||||
if (!map.custommode || map.custommodeforreal)
|
||||
{
|
||||
active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.isDown(SDLK_y))
|
||||
{
|
||||
if (!debug_held)
|
||||
{
|
||||
debug_held = true;
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_held = false;
|
||||
}
|
||||
|
||||
if (!active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.isDown(SDLK_TAB))
|
||||
{
|
||||
if (!tab_held)
|
||||
{
|
||||
tab_held = true;
|
||||
should_pause = !should_pause;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tab_held = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < obj.entities.size(); i++)
|
||||
{
|
||||
SDL_Rect bounding_box = {
|
||||
obj.entities[i].xp + obj.entities[i].cx,
|
||||
obj.entities[i].yp + obj.entities[i].cy,
|
||||
obj.entities[i].w,
|
||||
obj.entities[i].h
|
||||
};
|
||||
|
||||
if (key.leftbutton)
|
||||
{
|
||||
if (mouse_within(&bounding_box))
|
||||
{
|
||||
if (!mouse_held)
|
||||
{
|
||||
mouse_held = true;
|
||||
held_entity = i;
|
||||
grabber_offset_x = key.mx - obj.entities[i].xp;
|
||||
grabber_offset_y = key.my - obj.entities[i].yp;
|
||||
|
||||
if (!key.keymap[SDLK_LSHIFT] && !key.keymap[SDLK_RSHIFT])
|
||||
{
|
||||
for (int j = 0; j < obj.blocks.size(); j++)
|
||||
{
|
||||
if (obj.entities[i].xp == obj.blocks[j].rect.x && obj.entities[i].yp == obj.blocks[j].rect.y)
|
||||
{
|
||||
held_block = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse_held = false;
|
||||
held_entity = -1;
|
||||
held_block = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (held_entity == -1)
|
||||
{
|
||||
for (int i = 0; i < obj.blocks.size(); i++)
|
||||
{
|
||||
SDL_Rect bounding_box = {
|
||||
obj.blocks[i].rect.x,
|
||||
obj.blocks[i].rect.y,
|
||||
obj.blocks[i].rect.w,
|
||||
obj.blocks[i].rect.h
|
||||
};
|
||||
|
||||
if (key.leftbutton)
|
||||
{
|
||||
if (mouse_within(&bounding_box))
|
||||
{
|
||||
if (!mouse_held)
|
||||
{
|
||||
mouse_held = true;
|
||||
held_block = i;
|
||||
grabber_offset_x = key.mx - obj.blocks[i].rect.x;
|
||||
grabber_offset_y = key.my - obj.blocks[i].rect.y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
held_entity = -1;
|
||||
mouse_held = false;
|
||||
held_block = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (INBOUNDS_VEC(held_entity, obj.entities))
|
||||
{
|
||||
obj.entities[held_entity].xp = key.mx - grabber_offset_x;
|
||||
obj.entities[held_entity].yp = key.my - grabber_offset_y;
|
||||
|
||||
if (key.isDown(SDLK_LSHIFT) || key.isDown(SDLK_RSHIFT))
|
||||
{
|
||||
obj.entities[held_entity].xp -= obj.entities[held_entity].xp % 8;
|
||||
obj.entities[held_entity].yp -= obj.entities[held_entity].yp % 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (INBOUNDS_VEC(held_block, obj.blocks))
|
||||
{
|
||||
int new_xp = key.mx - grabber_offset_x;
|
||||
int new_yp = key.my - grabber_offset_y;
|
||||
|
||||
if (key.isDown(SDLK_LSHIFT) || key.isDown(SDLK_RSHIFT))
|
||||
{
|
||||
new_xp -= new_xp % 8;
|
||||
new_yp -= new_yp % 8;
|
||||
}
|
||||
|
||||
obj.blocks[held_block].xp = new_xp;
|
||||
obj.blocks[held_block].yp = new_yp;
|
||||
obj.blocks[held_block].rect.x = new_xp;
|
||||
obj.blocks[held_block].rect.y = new_yp;
|
||||
}
|
||||
}
|
||||
|
||||
void render_info(int y, const char* text, const char* value)
|
||||
{
|
||||
char buffer[SCREEN_WIDTH_CHARS + 1];
|
||||
vformat_buf(buffer, sizeof(buffer), text, "value:str", value);
|
||||
font::print(PR_BOR | PR_FONT_8X8, 5, 32 + (10 * y), buffer, 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2));
|
||||
}
|
||||
|
||||
void render(void)
|
||||
{
|
||||
if (!active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int hovered = -1;
|
||||
bool hovered_entity = true;
|
||||
SDL_Rect hover_box;
|
||||
|
||||
for (int i = 0; i < obj.entities.size(); i++)
|
||||
{
|
||||
SDL_Rect bounding_box = {
|
||||
obj.entities[i].xp + obj.entities[i].cx,
|
||||
obj.entities[i].yp + obj.entities[i].cy,
|
||||
obj.entities[i].w,
|
||||
obj.entities[i].h
|
||||
};
|
||||
|
||||
bool hovering = false;
|
||||
|
||||
if (hovered == -1 && mouse_within(&bounding_box))
|
||||
{
|
||||
hovering = true;
|
||||
hovered = i;
|
||||
hovered_entity = true;
|
||||
hover_box = bounding_box;
|
||||
}
|
||||
|
||||
graphics.draw_rect(bounding_box.x, bounding_box.y, bounding_box.w, bounding_box.h, graphics.getRGB(15, 90, 90));
|
||||
}
|
||||
|
||||
for (int i = 0; i < obj.blocks.size(); i++)
|
||||
{
|
||||
SDL_Rect bounding_box = {
|
||||
obj.blocks[i].rect.x,
|
||||
obj.blocks[i].rect.y,
|
||||
obj.blocks[i].rect.w,
|
||||
obj.blocks[i].rect.h
|
||||
};
|
||||
|
||||
bool hovering = false;
|
||||
|
||||
if (hovered == -1 && mouse_within(&bounding_box))
|
||||
{
|
||||
hovering = true;
|
||||
hovered = i;
|
||||
hovered_entity = false;
|
||||
hover_box = bounding_box;
|
||||
}
|
||||
|
||||
graphics.draw_rect(bounding_box.x, bounding_box.y, bounding_box.w, bounding_box.h, graphics.getRGB(90, 15, 15));
|
||||
}
|
||||
|
||||
font::print(PR_BOR | PR_FONT_8X8, 5, 14, loc::gettext("[Press TAB to toggle movement]"), 220 - (help.glow), 220 - (help.glow), 255 - (help.glow / 2));
|
||||
|
||||
if (hovered != -1)
|
||||
{
|
||||
int line = 0;
|
||||
if (hovered_entity)
|
||||
{
|
||||
entclass* entity = &obj.entities[hovered];
|
||||
render_info(line++, "Index: {value}", help.String(hovered).c_str());
|
||||
render_info(line++, "X: {value}", help.String(entity->xp).c_str());
|
||||
render_info(line++, "Y: {value}", help.String(entity->yp).c_str());
|
||||
render_info(line++, "Width: {value}", help.String(entity->w).c_str());
|
||||
render_info(line++, "Height: {value}", help.String(entity->h).c_str());
|
||||
line++;
|
||||
render_info(line++, "Rule: {value}", help.String(entity->rule).c_str());
|
||||
render_info(line++, "Type: {value}", help.String(entity->type).c_str());
|
||||
render_info(line++, "Behave: {value}", help.String(entity->behave).c_str());
|
||||
render_info(line++, "Para: {value}", help.String(entity->para).c_str());
|
||||
line++;
|
||||
render_info(line++, "Tile: {value}", help.String(entity->tile).c_str());
|
||||
render_info(line++, "Draw Frame: {value}", help.String(entity->drawframe).c_str());
|
||||
render_info(line++, "Size: {value}", help.String(entity->size).c_str());
|
||||
render_info(line++, "Direction: {value}", help.String(entity->dir).c_str());
|
||||
|
||||
graphics.draw_rect(hover_box.x, hover_box.y, hover_box.w, hover_box.h, graphics.getRGB(32, 255 - help.glow, 255 - help.glow));
|
||||
}
|
||||
else
|
||||
{
|
||||
blockclass* block = &obj.blocks[hovered];
|
||||
render_info(line++, "Index: {value}", help.String(hovered).c_str());
|
||||
render_info(line++, "X: {value}", help.String(block->rect.x).c_str());
|
||||
render_info(line++, "Y: {value}", help.String(block->rect.y).c_str());
|
||||
render_info(line++, "Width: {value}", help.String(block->rect.w).c_str());
|
||||
render_info(line++, "Height: {value}", help.String(block->rect.h).c_str());
|
||||
|
||||
line++;
|
||||
|
||||
if (block->type == TRIGGER || block->type == ACTIVITY)
|
||||
{
|
||||
render_info(line++, "Script: {value}", block->script.c_str());
|
||||
render_info(line++, "State: {value}", help.String(block->trigger).c_str());
|
||||
}
|
||||
else if (block->type == DIRECTIONAL)
|
||||
{
|
||||
render_info(line++, "Direction: {value}", help.String(block->trigger).c_str());
|
||||
}
|
||||
|
||||
graphics.draw_rect(hover_box.x, hover_box.y, hover_box.w, hover_box.h, graphics.getRGB(255 - help.glow, 32, 32));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
14
desktop_version/src/LevelDebugger.h
Normal file
14
desktop_version/src/LevelDebugger.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef LEVELDEBUGGER_H
|
||||
#define LEVELDEBUGGER_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
namespace level_debugger
|
||||
{
|
||||
bool is_pausing(void);
|
||||
bool is_active(void);
|
||||
void input(void);
|
||||
void render(void);
|
||||
}
|
||||
|
||||
#endif /* LEVELDEBUGGER_H */
|
|
@ -14,6 +14,7 @@
|
|||
#include "GraphicsUtil.h"
|
||||
#include "InterimVersion.h"
|
||||
#include "KeyPoll.h"
|
||||
#include "LevelDebugger.h"
|
||||
#include "Localization.h"
|
||||
#include "LocalizationStorage.h"
|
||||
#include "MakeAndPlay.h"
|
||||
|
@ -2472,6 +2473,7 @@ void gamerender(void)
|
|||
graphics.drawtrophytext();
|
||||
}
|
||||
|
||||
level_debugger::render();
|
||||
|
||||
graphics.renderwithscreeneffects();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue