mirror of
https://github.com/raysan5/raylib.git
synced 2026-01-23 23:59:18 -05:00
Upload GGJ18 game: transmission mission
Game developed in the GGJ18, it has some bugs and ending screen is incomplete... I'll try to keep working a bit more on it.
This commit is contained in:
423
games/transmission/screens/screen_gameplay.c
Normal file
423
games/transmission/screens/screen_gameplay.c
Normal file
@ -0,0 +1,423 @@
|
||||
/**********************************************************************************************
|
||||
*
|
||||
* raylib - Advance Game template
|
||||
*
|
||||
* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload)
|
||||
*
|
||||
* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose, including commercial
|
||||
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
* as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "screens.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define MAX_CODING_WORDS 12
|
||||
//#define MAX_MISSION_WORDS 8
|
||||
#define MAX_LINE_CHAR 30
|
||||
|
||||
/*
|
||||
// NOTE: Coding words are generic and the same words
|
||||
// are used for all missions,
|
||||
typedef enum CodingWords {
|
||||
POLLO = 0,
|
||||
CONEJO,
|
||||
HUEVO,
|
||||
NIDO,
|
||||
AIRE,
|
||||
ARMARIO,
|
||||
AGUJERO,
|
||||
COSA,
|
||||
WORD,
|
||||
} CodingWords;
|
||||
*/
|
||||
|
||||
static char *codingWords[MAX_CODING_WORDS] = {
|
||||
"pollo\0",
|
||||
"conejo\0",
|
||||
"huevo\0",
|
||||
"nido\0",
|
||||
"aire\0",
|
||||
"armario\0",
|
||||
"agujero\0",
|
||||
"platano\0",
|
||||
"pastel\0",
|
||||
"mercado\0",
|
||||
"raton\0",
|
||||
"melon\0"
|
||||
};
|
||||
|
||||
// Words to be coded or coding words
|
||||
/*typedef struct Word {
|
||||
int id;
|
||||
Rectangle rec;
|
||||
Rectangle iniRec;
|
||||
bool hover;
|
||||
bool picked;
|
||||
char text[32]; // text
|
||||
} Word;*/
|
||||
|
||||
/*
|
||||
// Mission information
|
||||
typedef struct Mission {
|
||||
int id;
|
||||
char brief[512]; // Mission briefing
|
||||
char key[32]; // Mission keyword
|
||||
char msg[256]; // Message to be coded
|
||||
int wordsCount; // Number of words to coded
|
||||
int sols[8]; // Solution code, depends on wordsCount
|
||||
} Mission;
|
||||
*/
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition (local to this module)
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Gameplay screen global variables
|
||||
static int framesCounter;
|
||||
static int finishScreen;
|
||||
|
||||
static Texture2D texBackground;
|
||||
static SpriteFont fontMessage;
|
||||
static Texture2D texWordsAtlas;
|
||||
static Texture2D texVignette;
|
||||
|
||||
static Sound fxGrab;
|
||||
static Sound fxPlace;
|
||||
static Sound fxLeave;
|
||||
|
||||
static Music musSpy;
|
||||
|
||||
static Word words[MAX_CODING_WORDS] = { 0 };
|
||||
|
||||
// Hay que hacerlo global, para poder consultar el resultado desde la endingscreen
|
||||
//static Word messageWords[MAX_MISSION_WORDS] = { 0 };
|
||||
|
||||
static Mission *missions = NULL;
|
||||
|
||||
static bool canSend = false;
|
||||
|
||||
Vector2 msgOffset = { 430, 300 };
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Gameplay Screen Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Gameplay Screen Initialization logic
|
||||
void InitGameplayScreen(void)
|
||||
{
|
||||
framesCounter = 0;
|
||||
finishScreen = 0;
|
||||
|
||||
fontMessage = LoadSpriteFontEx("resources/fonts/traveling_typewriter.ttf", 30, 250, 0);
|
||||
|
||||
texBackground = LoadTexture("resources/textures/message_background.png");
|
||||
texVignette = LoadTexture("resources/textures/message_vignette.png");
|
||||
|
||||
fxGrab = LoadSound("resources/audio/fx_grab.ogg");
|
||||
fxPlace = LoadSound("resources/audio/fx_place.ogg");
|
||||
fxLeave = LoadSound("resources/audio/fx_leave.ogg");
|
||||
|
||||
musSpy = LoadMusicStream("resources/audio/s_p_y.xm");
|
||||
PlayMusicStream(musSpy);
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
#define WORD_ATLAS_FROM_FILE
|
||||
#endif
|
||||
#if defined(WORD_ATLAS_FROM_FILE)
|
||||
texWordsAtlas = LoadTexture("resources/textures/mission_words.png");
|
||||
#else
|
||||
// Generate coding words atlas directly from text
|
||||
Image imWordsBase = LoadImage("resources/textures/words_base.png");
|
||||
Image imWords = GenImageColor(imWordsBase.width, imWordsBase.height*MAX_CODING_WORDS, WHITE);
|
||||
|
||||
for (int i = 0; i < MAX_CODING_WORDS; i++)
|
||||
{
|
||||
ImageDraw(&imWords, imWordsBase,
|
||||
(Rectangle){ 0, 0, imWordsBase.width, imWordsBase.height },
|
||||
(Rectangle){ 0, imWordsBase.height*i, imWordsBase.width, imWordsBase.height });
|
||||
|
||||
ImageDrawTextEx(&imWords,(Vector2){ imWordsBase.width/2 - MeasureTextEx(fontMessage, codingWords[i],
|
||||
fontMessage.baseSize, 0).x/2, imWordsBase.height*i }, fontMessage, codingWords[i],
|
||||
fontMessage.baseSize, 0, BLACK);
|
||||
}
|
||||
|
||||
texWordsAtlas = LoadTextureFromImage(imWords);
|
||||
|
||||
UnloadImage(imWordsBase);
|
||||
UnloadImage(imWords);
|
||||
#endif
|
||||
|
||||
// Initialize missions
|
||||
// WARNING: Some problem with imWords image generation (memory leak?) could cause
|
||||
// that loading missions before/after generation breaks game, on web is the other way round... :(
|
||||
missions = LoadMissions("resources/missions.txt");
|
||||
TraceLog(LOG_WARNING, "Words count %i", missions[currentMission].wordsCount);
|
||||
|
||||
// Initialize coding words
|
||||
for (int i = 0; i < MAX_CODING_WORDS; i++)
|
||||
{
|
||||
words[i].id = -1; // Not placed anywhere
|
||||
|
||||
words[i].rec.x = 110 + 940*(i/(MAX_CODING_WORDS/2));
|
||||
words[i].rec.y = 200 + 60*(i%(MAX_CODING_WORDS/2));
|
||||
words[i].rec.width = 140; // texWordsAtlas.width/MAX_MISSIONS
|
||||
words[i].rec.height = 35; // texWordsAtlas.height/MAX_MISSION_WORDS
|
||||
words[i].iniRec = words[i].rec;
|
||||
words[i].hover = false; // Mouse hover detected
|
||||
words[i].picked = false; // Mouse picked
|
||||
|
||||
//words[i].text = ''; //codingWords[i]; // Fill text if required...
|
||||
}
|
||||
|
||||
// Analize missions[currentMission].msg string for words!
|
||||
int msgLen = strlen(missions[currentMission].msg);
|
||||
|
||||
// Add '/' each MAX_LINE_CHAR chars
|
||||
int currentLine = 1;
|
||||
int i = currentLine * MAX_LINE_CHAR;
|
||||
|
||||
while (i < msgLen - 1)
|
||||
{
|
||||
if (missions[currentMission].msg[i] == ' ')
|
||||
{
|
||||
missions[currentMission].msg[i] = '/';
|
||||
currentLine++;
|
||||
i = currentLine*MAX_LINE_CHAR;
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
|
||||
int currentWord = 0;
|
||||
int offsetX = 0;
|
||||
int offsetY = 0;
|
||||
bool foundWord = false;
|
||||
int wordInitPosX = 0;
|
||||
int wordInitPosY = 0;
|
||||
|
||||
// TODO: messageWords should be reseted every mission
|
||||
//memcpy(messageWords, 0, sizeof(Word)*MAX_MISSION_WORDS);
|
||||
|
||||
for (int i = 0; i < msgLen; i++)
|
||||
{
|
||||
char c = missions[currentMission].msg[i];
|
||||
if (foundWord && (c == ' ' || c == '.'))
|
||||
{
|
||||
foundWord = false;
|
||||
|
||||
messageWords[currentWord - 1].rec.width = (int)MeasureTextEx(fontMessage, SubText(missions[currentMission].msg, wordInitPosX, (i - wordInitPosX)), 30, 0).x;
|
||||
messageWords[currentWord - 1].rec.height = fontMessage.baseSize;
|
||||
|
||||
//TODO: Guardar en message
|
||||
strncpy(messageWords[currentWord - 1].text, SubText(missions[currentMission].msg, wordInitPosX, (i - wordInitPosX)), i - wordInitPosX);
|
||||
}
|
||||
|
||||
if (c == '@') // One word to change
|
||||
{
|
||||
foundWord = true;
|
||||
missions[currentMission].msg[i] = ' ';
|
||||
|
||||
offsetX = (int)MeasureTextEx(fontMessage, SubText(missions[currentMission].msg, wordInitPosY, (i + 1) - wordInitPosY), 30, 0).x;
|
||||
|
||||
messageWords[currentWord].rec.x = offsetX;
|
||||
messageWords[currentWord].rec.y = offsetY;
|
||||
|
||||
wordInitPosX = i + 1;
|
||||
|
||||
currentWord++;
|
||||
}
|
||||
else if (c == '/')
|
||||
{
|
||||
missions[currentMission].msg[i] = '\n';
|
||||
wordInitPosY = i;
|
||||
offsetY += (fontMessage.baseSize + fontMessage.baseSize/2); // raylib internal increment on line break...
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < missions[currentMission].wordsCount; i++)
|
||||
{
|
||||
messageWords[i].id = -1; // Not required for message words, id is the array position
|
||||
|
||||
// Recalculate words rectangles considering text offset on screen
|
||||
messageWords[i].rec.x += msgOffset.x;
|
||||
messageWords[i].rec.y += msgOffset.y;
|
||||
|
||||
// Recalculate words rectangle considering new width height
|
||||
messageWords[i].rec.x -= (texWordsAtlas.width - messageWords[i].rec.width)/2;
|
||||
messageWords[i].rec.y -= ((texWordsAtlas.height / MAX_CODING_WORDS) - messageWords[i].rec.height)/2;
|
||||
|
||||
//Recalculate width height
|
||||
messageWords[i].rec.width = texWordsAtlas.width;
|
||||
messageWords[i].rec.height = texWordsAtlas.height / MAX_CODING_WORDS;
|
||||
|
||||
messageWords[i].hover = false; // Mouse hover detected
|
||||
messageWords[i].picked = false; // Mouse picked
|
||||
}
|
||||
}
|
||||
|
||||
// Gameplay Screen Update logic
|
||||
void UpdateGameplayScreen(void)
|
||||
{
|
||||
UpdateMusicStream(musSpy);
|
||||
|
||||
for (int i = 0; i < MAX_CODING_WORDS; i++)
|
||||
{
|
||||
if (CheckCollisionPointRec(GetMousePosition(), words[i].rec))
|
||||
{
|
||||
words[i].hover = true;
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
|
||||
{
|
||||
words[i].picked = true;
|
||||
PlaySound(fxGrab);
|
||||
}
|
||||
}
|
||||
else words[i].hover = false;
|
||||
|
||||
|
||||
if (words[i].picked)
|
||||
{
|
||||
for (int j = 0; j < missions[currentMission].wordsCount; j++)
|
||||
{
|
||||
if (CheckCollisionPointRec(GetMousePosition(), messageWords[j].rec)) messageWords[j].hover = true;
|
||||
else messageWords[j].hover = false;
|
||||
}
|
||||
|
||||
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
|
||||
{
|
||||
words[i].picked = false;
|
||||
|
||||
for (int j = 0; j < missions[currentMission].wordsCount; j++)
|
||||
{
|
||||
messageWords[j].hover = false;
|
||||
|
||||
if (CheckCollisionPointRec(GetMousePosition(), messageWords[j].rec))
|
||||
{
|
||||
PlaySound(fxPlace);
|
||||
|
||||
words[i].rec.x = messageWords[j].rec.x;
|
||||
words[i].rec.y = messageWords[j].rec.y;
|
||||
|
||||
if (messageWords[j].id != -1)
|
||||
{
|
||||
int id = messageWords[j].id;
|
||||
words[id].rec = words[id].iniRec;
|
||||
}
|
||||
|
||||
messageWords[j].id = i;
|
||||
for (int k = 0; k < missions[currentMission].wordsCount; k++)
|
||||
{
|
||||
if (j != k && messageWords[j].id == messageWords[k].id)
|
||||
{
|
||||
messageWords[k].id = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySound(fxLeave);
|
||||
|
||||
words[i].rec = words[i].iniRec;
|
||||
if (i == messageWords[j].id) messageWords[j].id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move word picked with mouse
|
||||
if (words[i].picked)
|
||||
{
|
||||
words[i].rec.x = GetMouseX() - words[i].rec.width/2;
|
||||
words[i].rec.y = GetMouseY() - words[i].rec.height/2;
|
||||
|
||||
// TODO: Check if label is placed in some mission word position
|
||||
//if (CheckCollisionRecs(words[i].rec))
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (words[i].id != -1)
|
||||
}
|
||||
}
|
||||
|
||||
canSend = true;
|
||||
for(int j = 0; j < missions[currentMission].wordsCount; j++)
|
||||
{
|
||||
if(messageWords[j].id == -1)
|
||||
{
|
||||
canSend = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canSend && (IsKeyPressed(KEY_ENTER) || IsButtonPressed()))
|
||||
{
|
||||
finishScreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Gameplay Screen Draw logic
|
||||
void DrawGameplayScreen(void)
|
||||
{
|
||||
DrawTexture(texBackground, 0, 0, WHITE);
|
||||
|
||||
DrawTextEx(fontMessage, missions[currentMission].msg, msgOffset, fontMessage.baseSize, 0, BLACK);
|
||||
|
||||
for (int i = 0; i < missions[currentMission].wordsCount; i++)
|
||||
{
|
||||
Rectangle recLines = messageWords[i].rec;
|
||||
DrawRectangleLines(recLines.x, recLines.y, recLines.width, recLines.height, Fade(RED, 0.35f));
|
||||
if(messageWords[i].hover) DrawRectangleRec(messageWords[i].rec, Fade(RED, 0.30f));
|
||||
DrawText(FormatText("%i", messageWords[i].id), i*25, 0, 30, RED);
|
||||
}
|
||||
for (int i = 0; i < MAX_CODING_WORDS; i++)
|
||||
{
|
||||
if (words[i].picked) DrawTextureRec(texWordsAtlas, (Rectangle){ 0, i*35, 140, 35 }, (Vector2){ words[i].rec.x, words[i].rec.y }, MAROON);
|
||||
else if (words[i].hover) DrawTextureRec(texWordsAtlas, (Rectangle){ 0, i*35, 140, 35 }, (Vector2){ words[i].rec.x, words[i].rec.y }, RED);
|
||||
else DrawTextureRec(texWordsAtlas, (Rectangle){ 0, i*35, 140, 35 }, (Vector2){ words[i].rec.x, words[i].rec.y }, WHITE);
|
||||
}
|
||||
|
||||
DrawTexturePro(texVignette, (Rectangle){0,0,texVignette.width, texVignette.height}, (Rectangle){0,0,GetScreenWidth(), GetScreenHeight()}, (Vector2){0,0}, 0, WHITE);
|
||||
|
||||
if (canSend) DrawButton("enviar");
|
||||
}
|
||||
|
||||
// Gameplay Screen Unload logic
|
||||
void UnloadGameplayScreen(void)
|
||||
{
|
||||
UnloadTexture(texBackground);
|
||||
UnloadTexture(texVignette);
|
||||
UnloadTexture(texWordsAtlas);
|
||||
|
||||
UnloadSound(fxGrab);
|
||||
UnloadSound(fxLeave);
|
||||
UnloadSound(fxPlace);
|
||||
|
||||
UnloadMusicStream(musSpy);
|
||||
|
||||
free(missions);
|
||||
}
|
||||
|
||||
// Gameplay Screen should finish?
|
||||
int FinishGameplayScreen(void)
|
||||
{
|
||||
return finishScreen;
|
||||
}
|
||||
Reference in New Issue
Block a user