mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2026-07-27 17:41:49 +03: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:
committed by
Misa Elizabeth Kai
parent
3c4ed36418
commit
91f87fa126
@@ -84,6 +84,7 @@ set(VVV_SRC
|
|||||||
src/Input.cpp
|
src/Input.cpp
|
||||||
src/KeyPoll.cpp
|
src/KeyPoll.cpp
|
||||||
src/Labclass.cpp
|
src/Labclass.cpp
|
||||||
|
src/LevelDebugger.cpp
|
||||||
src/Localization.cpp
|
src/Localization.cpp
|
||||||
src/LocalizationMaint.cpp
|
src/LocalizationMaint.cpp
|
||||||
src/LocalizationStorage.cpp
|
src/LocalizationStorage.cpp
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
#include "GlitchrunnerMode.h"
|
#include "GlitchrunnerMode.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
#include "LevelDebugger.h"
|
||||||
#include "Localization.h"
|
#include "Localization.h"
|
||||||
#include "LocalizationStorage.h"
|
#include "LocalizationStorage.h"
|
||||||
#include "KeyPoll.h"
|
#include "KeyPoll.h"
|
||||||
@@ -7491,7 +7492,7 @@ int Game::get_timestep(void)
|
|||||||
|
|
||||||
bool Game::physics_frozen(void)
|
bool Game::physics_frozen(void)
|
||||||
{
|
{
|
||||||
return roomname_translator::is_pausing();
|
return roomname_translator::is_pausing() || level_debugger::is_pausing();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Game::incompetitive(void)
|
bool Game::incompetitive(void)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "GraphicsUtil.h"
|
#include "GraphicsUtil.h"
|
||||||
#include "KeyPoll.h"
|
#include "KeyPoll.h"
|
||||||
|
#include "LevelDebugger.h"
|
||||||
#include "Localization.h"
|
#include "Localization.h"
|
||||||
#include "LocalizationMaint.h"
|
#include "LocalizationMaint.h"
|
||||||
#include "LocalizationStorage.h"
|
#include "LocalizationStorage.h"
|
||||||
@@ -2436,6 +2437,12 @@ void gameinput(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level_debugger::input();
|
||||||
|
if (level_debugger::is_pausing())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
game.press_map = false;
|
game.press_map = false;
|
||||||
if (key.isDown(KEYBOARD_ENTER) || key.isDown(SDLK_KP_ENTER) || key.isDown(game.controllerButton_map) )
|
if (key.isDown(KEYBOARD_ENTER) || key.isDown(SDLK_KP_ENTER) || key.isDown(game.controllerButton_map) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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 "GraphicsUtil.h"
|
||||||
#include "InterimVersion.h"
|
#include "InterimVersion.h"
|
||||||
#include "KeyPoll.h"
|
#include "KeyPoll.h"
|
||||||
|
#include "LevelDebugger.h"
|
||||||
#include "Localization.h"
|
#include "Localization.h"
|
||||||
#include "LocalizationStorage.h"
|
#include "LocalizationStorage.h"
|
||||||
#include "MakeAndPlay.h"
|
#include "MakeAndPlay.h"
|
||||||
@@ -2472,6 +2473,7 @@ void gamerender(void)
|
|||||||
graphics.drawtrophytext();
|
graphics.drawtrophytext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level_debugger::render();
|
||||||
|
|
||||||
graphics.renderwithscreeneffects();
|
graphics.renderwithscreeneffects();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user