From 3725f1f966c57abf966430fda2d10fa2af45ab03 Mon Sep 17 00:00:00 2001 From: Stephen Olsen Date: Wed, 9 Sep 2015 22:18:16 -0400 Subject: [PATCH] some first levels --- Readme.md | 4 ++- rockets.c | 31 ++++++++++++++++---- rockets.h | 62 ++++++--------------------------------- rockets_gui.h | 49 +++++++++++++++++++++++++++++++ rockets_levels.c | 14 +++++++++ rockets_levels.h | 75 +++++++++++++++++++++++++++++++++++++++++++++--- rockets_math.h | 4 +-- 7 files changed, 172 insertions(+), 67 deletions(-) create mode 100644 rockets_gui.h diff --git a/Readme.md b/Readme.md index f65a142..4887a13 100644 --- a/Readme.md +++ b/Readme.md @@ -49,4 +49,6 @@ the c version, currently only works on osx [9/08/15] Slowly getting back into this after a long weekend. I think I'm in the middle of debugging the collision detection but I just took a sec to print out better statistics for the performance counter stuff. This is going to be helpful later but I will probably display it as a searchable table in game rather than interact with it as a console log. That way I can corrilate it to other debug info and replay slow frames, etc. -[9/09/15] I was thinking about the game and all the things I want to do for it but what's really important is that it's fun and the puzzles are good. If the puzzles aren't good and the game isn't fun then any other platform / debugger / story / graphics / ui doesn't even matter so I need to refocus on making good levels. I started that by adding an easier way to programattically build levels. I introduced a new data structure to represent a level specification. There are going to be a rich set of functions to build these up. Then when the user loads a level these specs are translated into actuial entities. In that way we make little prefabs (using a unity term) that let me specify a ship is at this location, but when the level is loaded the actual collision geometry and stuff is set up correctly. These are live editable the same way my other code is so I should be able to iterate on level design this way. This will let me really get to work on the core of the game which has to be solid or everything else is a waste of time. \ No newline at end of file +[9/09/15] I was thinking about the game and all the things I want to do for it but what's really important is that it's fun and the puzzles are good. If the puzzles aren't good and the game isn't fun then any other platform / debugger / story / graphics / ui doesn't even matter so I need to refocus on making good levels. I started that by adding an easier way to programattically build levels. I introduced a new data structure to represent a level specification. There are going to be a rich set of functions to build these up. Then when the user loads a level these specs are translated into actuial entities. In that way we make little prefabs (using a unity term) that let me specify a ship is at this location, but when the level is loaded the actual collision geometry and stuff is set up correctly. These are live editable the same way my other code is so I should be able to iterate on level design this way. This will let me really get to work on the core of the game which has to be solid or everything else is a waste of time. + +[9/09/15] I'm starting to design puzzles now. I really don't like the design workflow I have. It's very hard to use and to visualize what I want the player to be able to do. It might work for awhile but I think I need to design a level editor. I've been making some progressively challenging levels that try to make the player learn a new way of flying the ship for each level. I don't really know how far something like this can be taken but that's really the mvp I need to create to see if this is even a viable game. I ran into some problems on level 5 though and that collision detection bug is stopping that level from working so I need to take a bit of time and fix that before I can progress. \ No newline at end of file diff --git a/rockets.c b/rockets.c index a9b67e9..edb415f 100644 --- a/rockets.c +++ b/rockets.c @@ -928,7 +928,7 @@ gui_nodes(GUIState* gui, NodeStore* ns) void setup_level(GameState* state) { - load_level(state, 1); + load_level(state, state->current_level); state->status = RUNNING; } @@ -946,7 +946,7 @@ game_setup(void* game_state, NVGcontext* vg) "SourceSansPro-Regular.ttf"); // Assert that the font got loaded. assert(font >= 0); - + state->current_level = 1; setup_level(state); return state; @@ -958,7 +958,7 @@ game_update_and_render(void* gamestate, NVGcontext* vg, gg_Input input, float dt) -{ +{ debug_setup_records(); debug_setup_drawing(); @@ -1005,7 +1005,21 @@ game_update_and_render(void* gamestate, } char* reset = "Reset"; - if (gui_button_with_text(state->gui, 660, 2.5, 10, 5, reset)) { + if (gui_button_with_text(state->gui, 660, 2.5, 10, 10, reset)) { + setup_level(state); + } + + char* previous = "Previous Level"; + if (gui_button_with_text(state->gui, 1230, 2.5, 10, 5, previous)) { + state->current_level--; + CLAMP(state->current_level, 0, num_levels); + setup_level(state); + } + + char* next = "Next Level"; + if (gui_button_with_text(state->gui, 1250, 2.5, 10, 10, next)) { + state->current_level++; + CLAMP(state->current_level, 0, num_levels); setup_level(state); } @@ -1028,6 +1042,7 @@ game_update_and_render(void* gamestate, entity->thrusters = new_thrusters; ship_move(entity, dt); + // this doesn't work anymore because collision detection stop it from getting here. // @HARDCODE: Fix with collision detection. // Goal is at (500, 600) if (bounds_contains(500 - 10, @@ -1100,8 +1115,6 @@ game_update_and_render(void* gamestate, int time_block = BEGIN_TIME_BLOCK(); CollisionRect collision_entity_piece = collision_entity->collision_pieces[cep]; - - // wudabout the entity_piece.offset // Check if they collide. float area_width = collision_entity_piece.width + entity_piece.width; @@ -1230,6 +1243,12 @@ game_update_and_render(void* gamestate, } nvgRestore(vg); + // Debug draw the mouse location. + nvgBeginPath(vg); + nvgCircle(vg, input.mouse_x, input.mouse_y, 3); + nvgFillColor(vg, nvgRGBf(1,1,1)); + nvgFill(vg); + /* debug_print_records(); */ } diff --git a/rockets.h b/rockets.h index 01c8754..5828677 100644 --- a/rockets.h +++ b/rockets.h @@ -3,10 +3,14 @@ * The collision detection stuff isn't working properly. @TODO: next steps. + * Make a level system where you can pick the level and you can change the level. + * Use collisions for gameplay stuff like hitting the goal to win a level or dying. + * Add boundries to the level. * Better debug setup. Logging, performance counters, easier debug visualizations. (watch casey on this stuff today) * Debug the collision detection code. - * Use collisions for gameplay stuff. + * Make levels. + * Start really making some levels and play with the game mechanics. Any platform work before having a viable game and levels is just wasted. @@ -49,6 +53,8 @@ of debug utils and the drawing stuff abstracted so I can ditch nanovg later. Real renderer is probably going to be a lot more complex. I want a nice looking game. For now this vector stuff works fine. + Sort of want my own renderer and then I can implement it for metal or opengl or whatever but + is a ton more work. Porting * Once I really have a game it would be great to get it running on a lot of platforms. @@ -58,8 +64,6 @@ I'll keep saying and believing this. HMH is the absolute best thing I've ever watched. Just keep watching it! - - */ #ifndef _game_h #define _game_h @@ -72,58 +76,8 @@ #include "rockets_nodes.h" #include "rockets_entities.h" #include "rockets_levels.h" +#include "rockets_gui.h" -// GUI stuff -// @TODO: rockets_gui - -typedef struct { - Node* node; - BoundingBox bb; - V2 draw_position; - int input_index; - Node* input_to; -} NodeBounds; - -typedef enum { NE_NAH } NodeEventType; - -typedef struct { - NodeEventType type; -} NodeEvent; - -typedef enum {GUI_NAH, - GUI_DRAGGING_NODE, - GUI_DRAGGING_INPUT, - GUI_DRAGGING_OUTPUT, - GUI_DRAGGING_SLIDER} GUI_State; - -typedef enum {DT_NAH, - DT_BODY, - DT_OUTPUT, - DT_INPUT, - DT_SLIDER} DragTarget_Type; - -typedef struct { - DragTarget_Type type; - int from_id; - int from_input_num; - V2 from_position; // can calculate from from_id but meh... - V2 position; - int value; -} DragTarget; - -typedef struct { - NVGcontext* vg; - gg_Input input; - GUI_State state; - DragTarget drag_target; -} GUIState; - -typedef enum { BS_NAH, BS_HOVER, BS_CLICK } ButtonState; - -typedef struct entity_pointer_ { - Entity* entity; - struct entity_pointer_* next_entity; -} EntityPointer; typedef enum {RUNNING, PAUSED, WON, DIED} LevelStatus; diff --git a/rockets_gui.h b/rockets_gui.h new file mode 100644 index 0000000..3875f38 --- /dev/null +++ b/rockets_gui.h @@ -0,0 +1,49 @@ +#ifndef _rockets_gui_h +#define _rockets_gui_h +// GUI stuff +// @TODO: rockets_gui + +typedef struct { + Node* node; + BoundingBox bb; + V2 draw_position; + int input_index; + Node* input_to; +} NodeBounds; + +typedef enum { NE_NAH } NodeEventType; + +typedef struct { + NodeEventType type; +} NodeEvent; + +typedef enum {GUI_NAH, + GUI_DRAGGING_NODE, + GUI_DRAGGING_INPUT, + GUI_DRAGGING_OUTPUT, + GUI_DRAGGING_SLIDER} GUI_State; + +typedef enum {DT_NAH, + DT_BODY, + DT_OUTPUT, + DT_INPUT, + DT_SLIDER} DragTarget_Type; + +typedef struct { + DragTarget_Type type; + int from_id; + int from_input_num; + V2 from_position; // can calculate from from_id but meh... + V2 position; + int value; +} DragTarget; + +typedef struct { + NVGcontext* vg; + gg_Input input; + GUI_State state; + DragTarget drag_target; +} GUIState; + +typedef enum { BS_NAH, BS_HOVER, BS_CLICK } ButtonState; +#endif diff --git a/rockets_levels.c b/rockets_levels.c index 632dda9..cfd6a30 100644 --- a/rockets_levels.c +++ b/rockets_levels.c @@ -24,6 +24,7 @@ void load_level(GameState* state, int level_number) entity_add_flags(ship, EntityFlag_COLLIDES); + // @NOTE: ship is 40 x 50 CollisionRect* s1 = &ship->collision_pieces[ship->num_collision_pieces++]; s1->offset = v2(-10, -15); s1->size = v2(20, 40); @@ -47,6 +48,19 @@ void load_level(GameState* state, int level_number) g->offset = v2(-10, -10); g->size = v2(20, 20); } break; + + case(ES_OBSTICLE): { + Entity* obsticle = push_entity(state); + obsticle->type = EntityType_BOUNDRY; + obsticle->position = entity.position; + obsticle->rotation = 0; + + entity_add_flags(obsticle, EntityFlag_COLLIDES); + + CollisionRect* o = &obsticle->collision_pieces[obsticle->num_collision_pieces++]; + o->offset = v2(-entity.size.x/2, -entity.size.y/2); + o->size = entity.size; + } } } } diff --git a/rockets_levels.h b/rockets_levels.h index c3f2cba..010f736 100644 --- a/rockets_levels.h +++ b/rockets_levels.h @@ -5,14 +5,14 @@ // These levelspecs are translated into full sets of entities when the level is loaded. // See rockets_levels.c to see how these are translated into game entities. typedef enum {ES_PLAYER_SHIP, - ES_GOAL} EntitySpecType; + ES_GOAL, + ES_OBSTICLE} EntitySpecType; typedef struct { EntitySpecType type; int id; - union { - V2 position; - }; + V2 position; + V2 size; } EntitySpec; typedef struct { @@ -47,12 +47,65 @@ add_goal(LevelSpec* level, float x, float y) return entity->id; } +int +add_obsticle(LevelSpec* level, float x, float y, float width, float height) +{ + EntitySpec* entity = push_entity_spec(level); + entity->type = ES_OBSTICLE; + entity->position = v2(x, y); + entity->size = v2(width, height); + return entity->id; +} + + +// gotta go up void level_1(LevelSpec* level) { add_player_ship(level, 300, 99); + add_goal(level, 300, 600); +} + +// gotta move over +void level_2(LevelSpec* level) +{ + add_player_ship(level, 300, 99); + add_goal(level, 500, 600); +} + +// gotta move up and over +void level_3(LevelSpec* level) +{ + add_player_ship(level, 300, 99); + add_goal(level, 500, 600); + add_obsticle(level, 300, 600, 20, 20); + add_obsticle(level, 500, 99, 20, 20); +} + +// gotta move up and over but not at the middle +// @QUESTIONABLE: this one is only a new step if you moved over at exactly the middle, not something +// everyone will hit. +void level_4(LevelSpec* level) +{ + add_player_ship(level, 300, 99); + add_goal(level, 500, 600); + add_obsticle(level, 300, 600, 20, 20); + add_obsticle(level, 500, 99, 20, 20); + add_obsticle(level, 400, 350, 20, 20); +} + +// gotta turn +void level_5(LevelSpec* level) +{ + // ship is 40 x 50 so need a 40px gap you gotta fly through + add_player_ship(level, 100, 99); add_goal(level, 500, 600); + + add_obsticle(level, 300, 165, 40, 330); + add_obsticle(level, 300, 535, 40, 330); + } +// @TODO: Better table here, this is annoying. LevelSpec get_level_spec(int level) { LevelSpec spec = {}; @@ -60,6 +113,18 @@ LevelSpec get_level_spec(int level) case(1): level_1(&spec); break; + case(2): + level_2(&spec); + break; + case(3): + level_3(&spec); + break; + case(4): + level_4(&spec); + break; + case(5): + level_5(&spec); + break; default: log_error("Error, asking for unknown level."); break; @@ -67,4 +132,6 @@ LevelSpec get_level_spec(int level) return spec; } +int num_levels = 1; + #endif diff --git a/rockets_math.h b/rockets_math.h index c735378..2e6c722 100644 --- a/rockets_math.h +++ b/rockets_math.h @@ -17,8 +17,8 @@ bounds_contains(float top_leftx, float top_lefty, float bottom_rightx, float bottom_righty, float x, float y) { - return (x > top_leftx && x < bottom_rightx && - y > top_lefty && y < bottom_righty); + return (x >= top_leftx && x <= bottom_rightx && + y >= top_lefty && y <= bottom_righty); } // Vectors