Migrate to SDL2 and deploy as WASM
All checks were successful
Build & deploy web version / Build WebAssembly & deploy (push) Successful in 1m8s
All checks were successful
Build & deploy web version / Build WebAssembly & deploy (push) Successful in 1m8s
This commit is contained in:
parent
81f4f20899
commit
c9b542eccf
24 changed files with 1411 additions and 483 deletions
71
.forgejo/workflows/deploy.yml
Normal file
71
.forgejo/workflows/deploy.yml
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
name: Build & deploy web version
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ['main']
|
||||||
|
pull_request:
|
||||||
|
branches: ['main']
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: 'pages'
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: Build WebAssembly & deploy
|
||||||
|
runs-on: docker
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Keep in sync with the version table in README.md.
|
||||||
|
EMSDK_VERSION: '6.0.6'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install cmake & friends
|
||||||
|
run: |
|
||||||
|
set -eo pipefail
|
||||||
|
SUDO=""
|
||||||
|
[ "$(id -u)" -eq 0 ] || SUDO="sudo"
|
||||||
|
$SUDO apt-get update
|
||||||
|
$SUDO apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates cmake git ninja-build python3 xz-utils
|
||||||
|
cmake --version
|
||||||
|
|
||||||
|
- name: Install Emscripten
|
||||||
|
run: |
|
||||||
|
set -eo pipefail
|
||||||
|
git clone --depth 1 https://github.com/emscripten-core/emsdk.git "$HOME/emsdk"
|
||||||
|
cd "$HOME/emsdk"
|
||||||
|
./emsdk install "$EMSDK_VERSION"
|
||||||
|
./emsdk activate "$EMSDK_VERSION"
|
||||||
|
. ./emsdk_env.sh
|
||||||
|
# emsdk_env.sh only touches this step's shell, so hand the activated
|
||||||
|
# toolchain over to the later steps explicitly.
|
||||||
|
{
|
||||||
|
echo "EMSDK=$EMSDK"
|
||||||
|
echo "EMSDK_NODE=$EMSDK_NODE"
|
||||||
|
echo "EM_CONFIG=${EM_CONFIG:-$EMSDK/.emscripten}"
|
||||||
|
echo "PATH=$PATH"
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: emcmake cmake -S . -B build-web -G Ninja -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build-web
|
||||||
|
|
||||||
|
- name: Check the expected files were produced
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
for file in index.html index.js index.wasm index.data; do
|
||||||
|
test -s "build-web/web/$file" || { echo "hiányzik: $file"; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Deploy to nginx pages mount
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
uses: http://forgejo:3000/andras/ci-actions/deploy-pages@main
|
||||||
|
with:
|
||||||
|
source: build-web/web
|
||||||
|
target: platform-game
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
79
CMakeLists.txt
Normal file
79
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
cmake_minimum_required(VERSION 3.21)
|
||||||
|
project(platform_game C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(GAME_VENDOR_SDL "Build pinned SDL2/SDL2_ttf from source instead of using system packages" ON)
|
||||||
|
|
||||||
|
set(GAME_SRC "${CMAKE_CURRENT_SOURCE_DIR}/Forráskód")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE GAME_SOURCES CONFIGURE_DEPENDS "${GAME_SRC}/*.c")
|
||||||
|
|
||||||
|
add_executable(game ${GAME_SOURCES})
|
||||||
|
|
||||||
|
target_include_directories(game PRIVATE "${GAME_SRC}")
|
||||||
|
target_compile_options(game PRIVATE -Wall)
|
||||||
|
|
||||||
|
if(EMSCRIPTEN)
|
||||||
|
set(GAME_EM_FLAGS "SHELL:-sUSE_SDL=2" "SHELL:-sUSE_SDL_TTF=2")
|
||||||
|
set(GAME_WEB_SHELL "${CMAKE_CURRENT_SOURCE_DIR}/web/shell.html")
|
||||||
|
set(GAME_WEB_PREJS "${CMAKE_CURRENT_SOURCE_DIR}/web/pre.js")
|
||||||
|
|
||||||
|
target_compile_options(game PRIVATE ${GAME_EM_FLAGS})
|
||||||
|
target_link_options(game PRIVATE
|
||||||
|
${GAME_EM_FLAGS}
|
||||||
|
"SHELL:-sALLOW_MEMORY_GROWTH=1"
|
||||||
|
"SHELL:-sEXIT_RUNTIME=0"
|
||||||
|
"SHELL:-sFORCE_FILESYSTEM=1"
|
||||||
|
"SHELL:-lidbfs.js"
|
||||||
|
"SHELL:--preload-file ${GAME_SRC}/resources@/resources"
|
||||||
|
"SHELL:--shell-file ${GAME_WEB_SHELL}"
|
||||||
|
"SHELL:--pre-js ${GAME_WEB_PREJS}"
|
||||||
|
)
|
||||||
|
set_target_properties(game PROPERTIES
|
||||||
|
OUTPUT_NAME index
|
||||||
|
SUFFIX ".html"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/web"
|
||||||
|
LINK_DEPENDS "${GAME_WEB_SHELL};${GAME_WEB_PREJS}"
|
||||||
|
)
|
||||||
|
elseif(GAME_VENDOR_SDL)
|
||||||
|
include(FetchContent)
|
||||||
|
set(FETCHCONTENT_QUIET OFF)
|
||||||
|
|
||||||
|
# As a subproject both libraries already default to no samples and no install
|
||||||
|
# rules, and BUILD_SHARED_LIBS=OFF is what turns SDL2 static-only, so these
|
||||||
|
# three are the only knobs that still differ from the defaults.
|
||||||
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_TEST OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL2TTF_VENDORED ON CACHE BOOL "" FORCE) # build freetype instead of finding it
|
||||||
|
|
||||||
|
FetchContent_Declare(SDL2
|
||||||
|
URL https://github.com/libsdl-org/SDL/releases/download/release-2.32.4/SDL2-2.32.4.tar.gz
|
||||||
|
URL_HASH SHA256=f15b478253e1ff6dac62257ded225ff4e7d0c5230204ac3450f1144ee806f934
|
||||||
|
)
|
||||||
|
FetchContent_Declare(SDL2_ttf
|
||||||
|
URL https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.24.0/SDL2_ttf-2.24.0.tar.gz
|
||||||
|
URL_HASH SHA256=0b2bf1e7b6568adbdbc9bb924643f79d9dedafe061fa1ed687d1d9ac4e453bfd
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(SDL2 SDL2_ttf)
|
||||||
|
|
||||||
|
target_link_libraries(game PRIVATE SDL2::SDL2-static SDL2::SDL2main SDL2_ttf::SDL2_ttf-static)
|
||||||
|
else()
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
find_package(SDL2_ttf REQUIRED)
|
||||||
|
target_link_libraries(game PRIVATE SDL2::SDL2 SDL2::SDL2main SDL2_ttf::SDL2_ttf)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
|
target_link_libraries(game PRIVATE m)
|
||||||
|
add_custom_command(TARGET game POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
"${GAME_SRC}/resources" "$<TARGET_FILE_DIR:game>/resources"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:game>/saves"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "modules/global.h"
|
#include "modules/global.h"
|
||||||
#include "modules/camera.h"
|
#include "modules/camera.h"
|
||||||
#include "modules/color.h"
|
#include "modules/color.h"
|
||||||
|
|
@ -55,8 +59,8 @@
|
||||||
* - auxSDL.c: a megfelelő sdl-es függvények meghívása, illetve az egér interakciók kezelése
|
* - auxSDL.c: a megfelelő sdl-es függvények meghívása, illetve az egér interakciók kezelése
|
||||||
* - auxFunctions.c: gyakran használ inline függvények
|
* - auxFunctions.c: gyakran használ inline függvények
|
||||||
* \section Kompatibilitás
|
* \section Kompatibilitás
|
||||||
* A program lefordításához szükséges az SDL.h, SDL_ttf.h, illetve SDL_gfxPrimitives.h könyvtárak. Nincs tesztelve, viszont valószínűleg
|
* A program lefordításához szükséges az SDL2 és az SDL2_ttf könyvtár, a rajzoló primitíveket a program magával hozza.
|
||||||
* az SDL 1.2 által platformokon működőképes az alkalmazás. A játék fix FPS-sel fut, ez jelenleg 50-re van beállítva, így átlagos teljesítményű gépeken is
|
* Natívan és Emscriptennel webre fordítva is működik. A játék fix FPS-sel fut, ez jelenleg 50-re van beállítva, így átlagos teljesítményű gépeken is
|
||||||
* el kell futnia, viszont ehhez szükség van egy átlagos képességű gépre, szóval ez egy lényeges rendszerkövetelmény.
|
* el kell futnia, viszont ehhez szükség van egy átlagos képességű gépre, szóval ez egy lényeges rendszerkövetelmény.
|
||||||
* A játék működéséhez szükségesek a megfelelő ttf-fájlok.
|
* A játék működéséhez szükségesek a megfelelő ttf-fájlok.
|
||||||
* \section Készítette
|
* \section Készítette
|
||||||
|
|
@ -71,31 +75,22 @@
|
||||||
|
|
||||||
bool isLMBDown = false, isRMBDown = false, prematureClick;
|
bool isLMBDown = false, isRMBDown = false, prematureClick;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
static Uint32 backgroundColor;
|
||||||
|
static Uint32 previousTicks;
|
||||||
|
static double accumulator = 0;
|
||||||
|
static bool quitRequested = false;
|
||||||
|
|
||||||
srand(time(NULL));
|
static void handleEvents() {
|
||||||
SDL_Cursor* cursor = openWindow();
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
SDL_TimerID timerID;
|
|
||||||
timerID = SDL_AddTimer((int)(1000.0 / FPS), timer, NULL);
|
|
||||||
keys = SDL_GetKeyState(NULL);
|
|
||||||
//setlocale(0, "");
|
|
||||||
|
|
||||||
Uint32 backgroundColor = SDL_MapRGB(screen -> format, 40, 0, 0);
|
|
||||||
|
|
||||||
createMenuWorld();
|
|
||||||
|
|
||||||
while (getGameState() != quit) {
|
|
||||||
SDL_WaitEvent(&event);
|
|
||||||
|
|
||||||
|
while(SDL_PollEvent(&event)) {
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
case SDL_USEREVENT:
|
case SDL_QUIT:
|
||||||
|
|
||||||
SDL_FillRect(screen, NULL, backgroundColor);
|
quitRequested = true;
|
||||||
doStuff(isLMBDown, isRMBDown, prematureClick);
|
|
||||||
SDL_UpdateRect(screen, 0, 0, 0, 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
|
||||||
if(event.button.button == SDL_BUTTON_LEFT) handleClicks(&prematureClick);
|
if(event.button.button == SDL_BUTTON_LEFT) handleClicks(&prematureClick);
|
||||||
|
|
@ -116,12 +111,68 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
|
|
||||||
if(strcmp(SDL_GetKeyName(event.key.keysym.unicode), "escape") == 0) whatToDoOnEscape();
|
if(event.key.keysym.sym == SDLK_ESCAPE) whatToDoOnEscape();
|
||||||
else processTyping(event);
|
else processTyping(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
|
||||||
|
processTextInput(event.text.text);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void frame() {
|
||||||
|
const double step = 1000.0 / FPS;
|
||||||
|
|
||||||
|
handleEvents();
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
Uint32 now = SDL_GetTicks();
|
||||||
|
double elapsed = now - previousTicks;
|
||||||
|
previousTicks = now;
|
||||||
|
if(elapsed > 5 * step) elapsed = 5 * step;
|
||||||
|
accumulator += elapsed;
|
||||||
|
|
||||||
|
bool hasDrawn = false;
|
||||||
|
while(accumulator >= step) {
|
||||||
|
accumulator -= step;
|
||||||
|
|
||||||
|
bool isLastStep = accumulator < step;
|
||||||
|
setRenderingEnabled(isLastStep);
|
||||||
|
|
||||||
|
if(isLastStep) SDL_FillRect(screen, NULL, backgroundColor);
|
||||||
|
doStuff(isLMBDown, isRMBDown, prematureClick);
|
||||||
|
hasDrawn = hasDrawn || isLastStep;
|
||||||
|
}
|
||||||
|
setRenderingEnabled(true);
|
||||||
|
|
||||||
|
if(hasDrawn) presentFrame();
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
if(getGameState() == quit || quitRequested) emscripten_cancel_main_loop();
|
||||||
|
#else
|
||||||
|
if(!hasDrawn) SDL_Delay(1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
openWindow();
|
||||||
|
keys = (unsigned char*) SDL_GetKeyboardState(NULL);
|
||||||
|
SDL_StartTextInput();
|
||||||
|
|
||||||
|
backgroundColor = SDL_MapRGB(screen -> format, 40, 0, 0);
|
||||||
|
|
||||||
|
createMenuWorld();
|
||||||
|
previousTicks = SDL_GetTicks();
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_set_main_loop(frame, 0, 1);
|
||||||
|
#else
|
||||||
|
while(getGameState() != quit && !quitRequested) frame();
|
||||||
|
|
||||||
//Felszabadítás
|
//Felszabadítás
|
||||||
freeFloaterList();
|
freeFloaterList();
|
||||||
|
|
@ -131,9 +182,9 @@ int main(int argc, char *argv[]) {
|
||||||
freeParticleList();
|
freeParticleList();
|
||||||
SDL_FreeSurface(text);
|
SDL_FreeSurface(text);
|
||||||
freeFonts();
|
freeFonts();
|
||||||
SDL_RemoveTimer(timerID);
|
closeWindow();
|
||||||
SDL_FreeCursor(cursor);
|
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,208 @@
|
||||||
#include "auxSDL.h"
|
#include "auxSDL.h"
|
||||||
|
#include "../camera.h"
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten/html5.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
mousePos mouse; /**< Az egér koordinátáit tárolja, így egyszerűbb, mint közvetlen az eventek figyelése. */
|
mousePos mouse; /**< Az egér koordinátáit tárolja, így egyszerűbb, mint közvetlen az eventek figyelése. */
|
||||||
|
|
||||||
|
static SDL_Window* window;
|
||||||
|
static SDL_Renderer* renderer;
|
||||||
|
static SDL_Texture* frameTexture;
|
||||||
|
static int textureWidth, textureHeight;
|
||||||
|
|
||||||
/** \brief https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlcreatecursor.html
|
#ifdef __EMSCRIPTEN__
|
||||||
* Hogy erre miért van szükség, az egy nagyon jó kérdés. Ha ehelyett a "SDL_ShowCursor(SDL_DISABLE);"-t
|
///A böngésző pixelarányát adja vissza, a szoftveres rajzolás miatt megszabott plafonig.
|
||||||
* használnám az egér random ugrálna néha néha, így viszont ezt nem teszi.
|
static double drawingPixelRatio() {
|
||||||
*/
|
double ratio = emscripten_get_device_pixel_ratio();
|
||||||
static SDL_Cursor* createCursor() {
|
return ratio > maxDevicePixelRatio ? maxDevicePixelRatio : ratio;
|
||||||
Uint8 data[4*32] = {0};
|
}
|
||||||
Uint8 mask[4*32] = {0};
|
#endif
|
||||||
return SDL_CreateCursor(data, mask, 32, 32, 0, 0);
|
|
||||||
|
static void moveToResourceDirectory() {
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
char* base = SDL_GetBasePath();
|
||||||
|
if(base != NULL) {
|
||||||
|
if(chdir(base) != 0) fprintf(stderr, "Nem sikerult a munkakonyvtar valtas!\n");
|
||||||
|
SDL_free(base);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Létrehozza a játék futtatásához szükséges környezetet.
|
/** \brief Gondoskodik róla, hogy a textúra legalább a kért méretű legyen.
|
||||||
* Megnézi az elérhető legnagyobb felbontást, azzal a felbontással létrehoz egy ablakot, illetve
|
* Böngészőben a textúra eldobása átméretezéskor elveszejti a webgl kontextust, ezért
|
||||||
* meghív pár, az inicializáláshoz szükséges függvényt.
|
* a textúrát egyszer, jó bőre foglaljuk, és utána már csak egy részét használjuk.
|
||||||
* \return kurzor amit fel kell később szabadítanunk
|
|
||||||
*/
|
*/
|
||||||
SDL_Cursor* openWindow() {
|
static void ensureTexture(int width, int height) {
|
||||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
if(frameTexture != NULL && width <= textureWidth && height <= textureHeight) return;
|
||||||
SDL_Rect** screenSizes = SDL_ListModes(NULL, SDL_FULLSCREEN);
|
|
||||||
|
|
||||||
screen = SDL_SetVideoMode(screenSizes[0] -> w, screenSizes[0] -> h, 0, SDL_FULLSCREEN);
|
if(width > textureWidth) textureWidth = width;
|
||||||
|
if(height > textureHeight) textureHeight = height;
|
||||||
|
|
||||||
if (!screen) {
|
SDL_DestroyTexture(frameTexture);
|
||||||
fprintf(stderr, "Nem sikerult megnyitni az ablakot!\n");
|
frameTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING, textureWidth, textureHeight);
|
||||||
|
|
||||||
|
if(frameTexture == NULL) {
|
||||||
|
fprintf(stderr, "Nem sikerult letrehozni a texturat: %s\n", SDL_GetError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief A megadott méretű rajzfelületet hozza létre a régi helyére.
|
||||||
|
* A rajzfelület mindig pontosan akkora, mint a megjelenítő felülete, így nincs se
|
||||||
|
* fekete csík, se átméretezés.
|
||||||
|
*/
|
||||||
|
static void createDrawingSurface(int width, int height) {
|
||||||
|
if(width < 1) width = 1;
|
||||||
|
if(height < 1) height = 1;
|
||||||
|
|
||||||
|
ensureTexture(width, height);
|
||||||
|
|
||||||
|
SDL_FreeSurface(screen);
|
||||||
|
screen = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||||
|
|
||||||
|
if(screen == NULL) {
|
||||||
|
fprintf(stderr, "Nem sikerult letrehozni a rajzfeluletet: %s\n", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_WM_SetCaption("Platform játék", "Schmelczer András: Platform játék");
|
SDL_RenderSetLogicalSize(renderer, width, height);
|
||||||
SDL_Cursor* cursor = createCursor();
|
|
||||||
SDL_SetCursor(cursor);
|
|
||||||
openFonts();
|
|
||||||
SDL_WM_GrabInput(SDL_GRAB_FULLSCREEN);
|
|
||||||
return cursor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///A játék időzítéséhez szükséges.
|
/** \brief Az ablak méretének változását követi le, képkockánként meghívva.
|
||||||
Uint32 timer(Uint32 ms, void* param) {
|
* Böngészőben a vászon css-méretéhez igazítja az ablakot, majd ha kell, új rajzfelületet
|
||||||
SDL_Event event;
|
* készít, a betűtípusokat a magassághoz igazítja, és a kamerával újraszámoltatja,
|
||||||
event.type = SDL_USEREVENT;
|
* hogy mennyi látszik a pályából.
|
||||||
SDL_PushEvent(&event);
|
*/
|
||||||
return ms;
|
void handleResize() {
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
double cssWidth, cssHeight;
|
||||||
|
if(emscripten_get_element_css_size("#canvas", &cssWidth, &cssHeight) == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||||
|
double ratio = drawingPixelRatio();
|
||||||
|
int wantedWidth = (int)(cssWidth * ratio);
|
||||||
|
int wantedHeight = (int)(cssHeight * ratio);
|
||||||
|
|
||||||
|
int currentWidth, currentHeight;
|
||||||
|
SDL_GetWindowSize(window, ¤tWidth, ¤tHeight);
|
||||||
|
|
||||||
|
if(wantedWidth > 0 && wantedHeight > 0 && (wantedWidth != currentWidth || wantedHeight != currentHeight))
|
||||||
|
SDL_SetWindowSize(window, wantedWidth, wantedHeight);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int outputWidth, outputHeight;
|
||||||
|
SDL_GetRendererOutputSize(renderer, &outputWidth, &outputHeight);
|
||||||
|
|
||||||
|
if(screen != NULL && screen -> w == outputWidth && screen -> h == outputHeight) return;
|
||||||
|
|
||||||
|
bool heightChanged = screen == NULL || screen -> h != outputHeight;
|
||||||
|
createDrawingSurface(outputWidth, outputHeight);
|
||||||
|
|
||||||
|
if(heightChanged) {
|
||||||
|
freeFonts();
|
||||||
|
openFonts();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshCameraForScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Létrehozza a játék futtatásához szükséges környezetet.
|
||||||
|
* Létrehoz egy ablakot a hozzá tartozó rajzfelülettel, illetve
|
||||||
|
* meghív pár, az inicializáláshoz szükséges függvényt.
|
||||||
|
*/
|
||||||
|
void openWindow() {
|
||||||
|
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||||
|
fprintf(stderr, "Nem sikerult inicializalni az SDL-t: %s\n", SDL_GetError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToResourceDirectory();
|
||||||
|
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||||
|
|
||||||
|
int windowWidth = defaultWindowWidth;
|
||||||
|
int windowHeight = defaultWindowHeight;
|
||||||
|
Uint32 windowFlags = 0;
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
double cssWidth, cssHeight;
|
||||||
|
if(emscripten_get_element_css_size("#canvas", &cssWidth, &cssHeight) == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||||
|
double ratio = drawingPixelRatio();
|
||||||
|
windowWidth = (int) (cssWidth * ratio);
|
||||||
|
windowHeight = (int) (cssHeight * ratio);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
windowFlags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
|
|
||||||
|
SDL_Rect usableBounds;
|
||||||
|
if(SDL_GetDisplayUsableBounds(0, &usableBounds) == 0) {
|
||||||
|
float fit = smallerF((float) usableBounds.w / defaultWindowWidth, (float) usableBounds.h / defaultWindowHeight);
|
||||||
|
if(fit < 1.0f) {
|
||||||
|
windowWidth = (int) (defaultWindowWidth * fit);
|
||||||
|
windowHeight = (int) (defaultWindowHeight * fit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* forcedSize = SDL_getenv("GAME_WINDOW");
|
||||||
|
if(forcedSize != NULL) sscanf(forcedSize, "%dx%d", &windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
window = SDL_CreateWindow("Platform játék",
|
||||||
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
|
windowWidth, windowHeight,
|
||||||
|
windowFlags);
|
||||||
|
|
||||||
|
if(window == NULL) {
|
||||||
|
fprintf(stderr, "Nem sikerult megnyitni az ablakot: %s\n", SDL_GetError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||||
|
if(renderer == NULL) renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
|
||||||
|
if(renderer == NULL) {
|
||||||
|
fprintf(stderr, "Nem sikerult letrehozni a renderert: %s\n", SDL_GetError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
int screenPixelWidth, screenPixelHeight;
|
||||||
|
emscripten_get_screen_size(&screenPixelWidth, &screenPixelHeight);
|
||||||
|
double screenRatio = drawingPixelRatio();
|
||||||
|
textureWidth = (int)(screenPixelWidth * screenRatio);
|
||||||
|
textureHeight = (int)(screenPixelHeight * screenRatio);
|
||||||
|
#else
|
||||||
|
SDL_DisplayMode desktop;
|
||||||
|
if(SDL_GetDesktopDisplayMode(0, &desktop) == 0) {
|
||||||
|
textureWidth = desktop.w;
|
||||||
|
textureHeight = desktop.h;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int outputWidth, outputHeight;
|
||||||
|
SDL_GetRendererOutputSize(renderer, &outputWidth, &outputHeight);
|
||||||
|
createDrawingSurface(outputWidth, outputHeight);
|
||||||
|
|
||||||
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
openFonts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void presentFrame() {
|
||||||
|
SDL_Rect used = {0, 0, screen -> w, screen -> h};
|
||||||
|
SDL_UpdateTexture(frameTexture, &used, screen -> pixels, screen -> pitch);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_RenderCopy(renderer, frameTexture, &used, NULL);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeWindow() {
|
||||||
|
SDL_FreeSurface(screen);
|
||||||
|
SDL_DestroyTexture(frameTexture);
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Frissití az egér pozicióját.
|
///Frissití az egér pozicióját.
|
||||||
|
|
@ -58,10 +218,11 @@ mousePos getMousePosition() {
|
||||||
|
|
||||||
///Lerajzolja a képernyőre az egeret, erre azért van szükség, mert az SDL csak fekete-fehér egérmutatót kezel.
|
///Lerajzolja a képernyőre az egeret, erre azért van szükség, mert az SDL csak fekete-fehér egérmutatót kezel.
|
||||||
void drawMouse(bool isBW) {
|
void drawMouse(bool isBW) {
|
||||||
Sint16 x1 = mouse.x - mouseSize / 2;
|
Sint16 size = larger(4, mouseSize * screen -> h / designHeight);
|
||||||
Sint16 x2 = mouse.x + mouseSize / 2;
|
Sint16 x1 = mouse.x - size / 2;
|
||||||
Sint16 y1 = mouse.y - mouseSize / 2;
|
Sint16 x2 = mouse.x + size / 2;
|
||||||
Sint16 y2 = mouse.y + mouseSize / 2;
|
Sint16 y1 = mouse.y - size / 2;
|
||||||
|
Sint16 y2 = mouse.y + size / 2;
|
||||||
boxColor(screen, x1, y1, x2, y2, isBW ? 0x7F7F7FFF : 0xFFFF00FF);
|
boxColor(screen, x1, y1, x2, y2, isBW ? 0x7F7F7FFF : 0xFFFF00FF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,24 @@
|
||||||
|
|
||||||
#define mouseSize 20 /**< Az egérmutató négyzetnek az oldalhosszusága. */
|
#define mouseSize 20 /**< Az egérmutató négyzetnek az oldalhosszusága. */
|
||||||
|
|
||||||
|
#define defaultWindowWidth 1920 /**< Az ablak alapértelmezett szélessége. */
|
||||||
|
#define defaultWindowHeight 1080 /**< Az ablak alapértelmezett magassága. */
|
||||||
|
|
||||||
|
/** \brief Böngészőben legfeljebb ennyi rajzfelület-pixel jusson egy css-pixelre.
|
||||||
|
* A teljes képet a processzor rajzolja, így a költsége a pixelek számával nő. Egy retina
|
||||||
|
* kijelzőn a natív felbontás négyszer annyi pixelt jelentene; helyette css-méretben rajzolunk,
|
||||||
|
* a vásznat pedig a böngésző nagyítja fel, ami már ingyen van.
|
||||||
|
*/
|
||||||
|
#define maxDevicePixelRatio 1.0
|
||||||
|
|
||||||
typedef struct mousePos {
|
typedef struct mousePos {
|
||||||
Uint16 x, y;
|
Uint16 x, y;
|
||||||
} mousePos;
|
} mousePos;
|
||||||
|
|
||||||
SDL_Cursor* openWindow();
|
void openWindow();
|
||||||
Uint32 timer(Uint32 ms, void* param);
|
void handleResize();
|
||||||
|
void presentFrame();
|
||||||
|
void closeWindow();
|
||||||
void setMousePosition(Uint16 x, Uint16 y);
|
void setMousePosition(Uint16 x, Uint16 y);
|
||||||
mousePos getMousePosition();
|
mousePos getMousePosition();
|
||||||
void drawMouse(bool isBW);
|
void drawMouse(bool isBW);
|
||||||
|
|
|
||||||
300
Forráskód/modules/auxiliary/gfxPrimitives.c
Normal file
300
Forráskód/modules/auxiliary/gfxPrimitives.c
Normal file
|
|
@ -0,0 +1,300 @@
|
||||||
|
#include "gfxPrimitives.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct target {
|
||||||
|
SDL_Surface* surface;
|
||||||
|
Uint32* pixels;
|
||||||
|
int pitch, w, h;
|
||||||
|
int rShift, gShift, bShift;
|
||||||
|
Uint32 aMask;
|
||||||
|
bool locked;
|
||||||
|
} target;
|
||||||
|
|
||||||
|
static bool renderingEnabled = true; /**< Kikapcsolva minden rajzoló primitív azonnal visszatér. */
|
||||||
|
|
||||||
|
/** \brief Ki-be kapcsolja a rajzolást.
|
||||||
|
* A behozott képkockákat a main.c "utolérő" ciklusa többször is végigszimulálja, de csak
|
||||||
|
* az utolsót mutatja meg. A közbülső lépések alatt kikapcsolva a rajzolás nem dolgozik feleslegesen.
|
||||||
|
*/
|
||||||
|
void setRenderingEnabled(bool enabled) {
|
||||||
|
renderingEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRenderingEnabled() {
|
||||||
|
return renderingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool beginTarget(SDL_Surface* dst, target* t) {
|
||||||
|
if(!renderingEnabled || dst == NULL || dst -> format -> BytesPerPixel != 4) return false;
|
||||||
|
|
||||||
|
t -> surface = dst;
|
||||||
|
t -> locked = SDL_MUSTLOCK(dst);
|
||||||
|
if(t -> locked && SDL_LockSurface(dst) != 0) return false;
|
||||||
|
|
||||||
|
t -> pixels = (Uint32*) dst -> pixels;
|
||||||
|
t -> pitch = dst -> pitch / 4;
|
||||||
|
t -> w = dst -> w;
|
||||||
|
t -> h = dst -> h;
|
||||||
|
t -> rShift = dst -> format -> Rshift;
|
||||||
|
t -> gShift = dst -> format -> Gshift;
|
||||||
|
t -> bShift = dst -> format -> Bshift;
|
||||||
|
t -> aMask = dst -> format -> Amask;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void endTarget(target* t) {
|
||||||
|
if(t -> locked) SDL_UnlockSurface(t -> surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Uint32 packColor(const target* t, Uint8 r, Uint8 g, Uint8 b) {
|
||||||
|
return t -> aMask | ((Uint32) r << t -> rShift) | ((Uint32) g << t -> gShift) | ((Uint32) b << t -> bShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void blendPixel(const target* t, int x, int y, Uint8 r, Uint8 g, Uint8 b, int a) {
|
||||||
|
if(a <= 0 || x < 0 || y < 0 || x >= t -> w || y >= t -> h) return;
|
||||||
|
|
||||||
|
Uint32* p = t -> pixels + y * t -> pitch + x;
|
||||||
|
|
||||||
|
if(a >= 255) {
|
||||||
|
*p = packColor(t, r, g, b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 c = *p;
|
||||||
|
int ia = 255 - a;
|
||||||
|
Uint32 dr = (c >> t -> rShift) & 0xFF;
|
||||||
|
Uint32 dg = (c >> t -> gShift) & 0xFF;
|
||||||
|
Uint32 db = (c >> t -> bShift) & 0xFF;
|
||||||
|
|
||||||
|
*p = packColor(t,
|
||||||
|
(Uint8) ((r * a + dr * ia + 127) / 255),
|
||||||
|
(Uint8) ((g * a + dg * ia + 127) / 255),
|
||||||
|
(Uint8) ((b * a + db * ia + 127) / 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blendHLine(const target* t, int xa, int xb, int y, Uint8 r, Uint8 g, Uint8 b, int a) {
|
||||||
|
if(y < 0 || y >= t -> h || a <= 0) return;
|
||||||
|
if(xa > xb) { int tmp = xa; xa = xb; xb = tmp; }
|
||||||
|
if(xa < 0) xa = 0;
|
||||||
|
if(xb > t -> w - 1) xb = t -> w - 1;
|
||||||
|
if(xa > xb) return;
|
||||||
|
|
||||||
|
Uint32* p = t -> pixels + y * t -> pitch + xa;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(a >= 255) {
|
||||||
|
Uint32 c = packColor(t, r, g, b);
|
||||||
|
for(i = xa; i <= xb; i++) *p++ = c;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int ia = 255 - a;
|
||||||
|
int ra = r * a, ga = g * a, ba = b * a;
|
||||||
|
|
||||||
|
for(i = xa; i <= xb; i++, p++) {
|
||||||
|
Uint32 c = *p;
|
||||||
|
*p = packColor(t,
|
||||||
|
(Uint8) ((ra + ((c >> t -> rShift) & 0xFF) * ia + 127) / 255),
|
||||||
|
(Uint8) ((ga + ((c >> t -> gShift) & 0xFF) * ia + 127) / 255),
|
||||||
|
(Uint8) ((ba + ((c >> t -> bShift) & 0xFF) * ia + 127) / 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void unpackColor(Uint32 color, Uint8* r, Uint8* g, Uint8* b, Uint8* a) {
|
||||||
|
*r = (color >> 24) & 0xFF;
|
||||||
|
*g = (color >> 16) & 0xFF;
|
||||||
|
*b = (color >> 8) & 0xFF;
|
||||||
|
*a = color & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int boxRGBA(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||||
|
target t;
|
||||||
|
if(!beginTarget(dst, &t)) return -1;
|
||||||
|
|
||||||
|
if(x1 > x2) { Sint16 tmp = x1; x1 = x2; x2 = tmp; }
|
||||||
|
if(y1 > y2) { Sint16 tmp = y1; y1 = y2; y2 = tmp; }
|
||||||
|
|
||||||
|
int yStart = y1 < 0 ? 0 : y1;
|
||||||
|
int yEnd = y2 > t.h - 1 ? t.h - 1 : y2;
|
||||||
|
|
||||||
|
int y;
|
||||||
|
for(y = yStart; y <= yEnd; y++) blendHLine(&t, x1, x2, y, r, g, b, a);
|
||||||
|
|
||||||
|
endTarget(&t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int boxColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
|
||||||
|
Uint8 r, g, b, a;
|
||||||
|
unpackColor(color, &r, &g, &b, &a);
|
||||||
|
return boxRGBA(dst, x1, y1, x2, y2, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lineRGBA(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||||
|
target t;
|
||||||
|
if(!beginTarget(dst, &t)) return -1;
|
||||||
|
|
||||||
|
int dx = abs(x2 - x1), dy = -abs(y2 - y1);
|
||||||
|
int sx = x1 < x2 ? 1 : -1, sy = y1 < y2 ? 1 : -1;
|
||||||
|
int err = dx + dy;
|
||||||
|
int x = x1, y = y1;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
blendPixel(&t, x, y, r, g, b, a);
|
||||||
|
if(x == x2 && y == y2) break;
|
||||||
|
int e2 = 2 * err;
|
||||||
|
if(e2 >= dy) { err += dy; x += sx; }
|
||||||
|
if(e2 <= dx) { err += dx; y += sy; }
|
||||||
|
}
|
||||||
|
|
||||||
|
endTarget(&t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
|
||||||
|
Uint8 r, g, b, a;
|
||||||
|
unpackColor(color, &r, &g, &b, &a);
|
||||||
|
return lineRGBA(dst, x1, y1, x2, y2, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filledCircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
|
||||||
|
Uint8 r, g, b, a;
|
||||||
|
unpackColor(color, &r, &g, &b, &a);
|
||||||
|
|
||||||
|
target t;
|
||||||
|
if(!beginTarget(dst, &t)) return -1;
|
||||||
|
|
||||||
|
int dy;
|
||||||
|
for(dy = -rad; dy <= rad; dy++) {
|
||||||
|
int span = (int) floor(sqrt((double) rad * rad - (double) dy * dy));
|
||||||
|
blendHLine(&t, x - span, x + span, y + dy, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
endTarget(&t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int aacircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color) {
|
||||||
|
Uint8 r, g, b, a;
|
||||||
|
unpackColor(color, &r, &g, &b, &a);
|
||||||
|
|
||||||
|
target t;
|
||||||
|
if(!beginTarget(dst, &t)) return -1;
|
||||||
|
|
||||||
|
int dx, dy;
|
||||||
|
for(dy = -rad - 1; dy <= rad + 1; dy++)
|
||||||
|
for(dx = -rad - 1; dx <= rad + 1; dx++) {
|
||||||
|
double d = sqrt((double) dx * dx + (double) dy * dy);
|
||||||
|
double coverage = 1.0 - fabs(d - rad);
|
||||||
|
if(coverage > 0.0)
|
||||||
|
blendPixel(&t, x + dx, y + dy, r, g, b, (int) (a * (coverage > 1.0 ? 1.0 : coverage)));
|
||||||
|
}
|
||||||
|
|
||||||
|
endTarget(&t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filledPolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||||
|
if(n < 3) return -1;
|
||||||
|
|
||||||
|
target t;
|
||||||
|
if(!beginTarget(dst, &t)) return -1;
|
||||||
|
|
||||||
|
//A játék végig négyszögeket rajzol, azoknak bőven elég a veremben álló tömb;
|
||||||
|
//képkockánként több tízezer malloc/free párt spórolunk vele.
|
||||||
|
double inlineCrossings[16];
|
||||||
|
double* crossings = inlineCrossings;
|
||||||
|
if(n > (int)(sizeof(inlineCrossings) / sizeof(*inlineCrossings))) {
|
||||||
|
crossings = (double*) malloc(n * sizeof(double));
|
||||||
|
if(crossings == NULL) { endTarget(&t); return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int minY = vy[0], maxY = vy[0];
|
||||||
|
int i;
|
||||||
|
for(i = 1; i < n; i++) {
|
||||||
|
if(vy[i] < minY) minY = vy[i];
|
||||||
|
if(vy[i] > maxY) maxY = vy[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int yStart = minY < 0 ? 0 : minY;
|
||||||
|
int yEnd = maxY > t.h - 1 ? t.h - 1 : maxY;
|
||||||
|
|
||||||
|
int y;
|
||||||
|
for(y = yStart; y <= yEnd; y++) {
|
||||||
|
int count = 0;
|
||||||
|
for(i = 0; i < n; i++) {
|
||||||
|
int j = (i + 1) % n;
|
||||||
|
int y1 = vy[i], y2 = vy[j], x1 = vx[i], x2 = vx[j];
|
||||||
|
if(y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; tmp = x1; x1 = x2; x2 = tmp; }
|
||||||
|
|
||||||
|
if((y >= y1 && y < y2) || (y == maxY && y > y1 && y <= y2))
|
||||||
|
crossings[count++] = x1 + ((double) (y - y1) * (x2 - x1)) / (y2 - y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count < 2) continue;
|
||||||
|
|
||||||
|
//Néhány elemre a beszúrásos rendezés gyorsabb, mint a qsort függvénypointeres hívogatása
|
||||||
|
int k;
|
||||||
|
for(i = 1; i < count; i++) {
|
||||||
|
double key = crossings[i];
|
||||||
|
for(k = i - 1; k >= 0 && crossings[k] > key; k--) crossings[k + 1] = crossings[k];
|
||||||
|
crossings[k + 1] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i + 1 < count; i += 2)
|
||||||
|
blendHLine(&t, (int) floor(crossings[i] + 0.5), (int) floor(crossings[i + 1] + 0.5), y, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(crossings != inlineCrossings) free(crossings);
|
||||||
|
endTarget(&t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aaLine(const target* t, double x0, double y0, double x1, double y1, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||||
|
bool steep = fabs(y1 - y0) > fabs(x1 - x0);
|
||||||
|
double tmp;
|
||||||
|
if(steep) { tmp = x0; x0 = y0; y0 = tmp; tmp = x1; x1 = y1; y1 = tmp; }
|
||||||
|
if(x0 > x1) { tmp = x0; x0 = x1; x1 = tmp; tmp = y0; y0 = y1; y1 = tmp; }
|
||||||
|
|
||||||
|
double dx = x1 - x0;
|
||||||
|
double gradient = dx == 0.0 ? 0.0 : (y1 - y0) / dx;
|
||||||
|
|
||||||
|
int xStart = (int) floor(x0 + 0.5), xEnd = (int) floor(x1 + 0.5);
|
||||||
|
double intersection = y0 + gradient * (xStart - x0);
|
||||||
|
|
||||||
|
int x;
|
||||||
|
for(x = xStart; x <= xEnd; x++) {
|
||||||
|
int base = (int) floor(intersection);
|
||||||
|
double frac = intersection - base;
|
||||||
|
|
||||||
|
if(steep) {
|
||||||
|
blendPixel(t, base, x, r, g, b, (int) (a * (1.0 - frac)));
|
||||||
|
blendPixel(t, base + 1, x, r, g, b, (int) (a * frac));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
blendPixel(t, x, base, r, g, b, (int) (a * (1.0 - frac)));
|
||||||
|
blendPixel(t, x, base + 1, r, g, b, (int) (a * frac));
|
||||||
|
}
|
||||||
|
|
||||||
|
intersection += gradient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int aapolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||||
|
if(n < 2) return -1;
|
||||||
|
|
||||||
|
target t;
|
||||||
|
if(!beginTarget(dst, &t)) return -1;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < n; i++) {
|
||||||
|
int j = (i + 1) % n;
|
||||||
|
aaLine(&t, vx[i], vy[i], vx[j], vy[j], r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
endTarget(&t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
Forráskód/modules/auxiliary/gfxPrimitives.h
Normal file
18
Forráskód/modules/auxiliary/gfxPrimitives.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef GFXPRIMITIVES_H_INCLUDED
|
||||||
|
#define GFXPRIMITIVES_H_INCLUDED
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void setRenderingEnabled(bool enabled);
|
||||||
|
bool isRenderingEnabled();
|
||||||
|
|
||||||
|
int boxColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
|
||||||
|
int boxRGBA(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||||
|
int lineColor(SDL_Surface* dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
|
||||||
|
int filledCircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color);
|
||||||
|
int aacircleColor(SDL_Surface* dst, Sint16 x, Sint16 y, Sint16 rad, Uint32 color);
|
||||||
|
int filledPolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||||
|
int aapolygonRGBA(SDL_Surface* dst, const Sint16* vx, const Sint16* vy, int n, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||||
|
|
||||||
|
#endif // GFXPRIMITIVES_H_INCLUDED
|
||||||
|
|
@ -3,12 +3,13 @@
|
||||||
|
|
||||||
///Indításnál betölti a szükséges betűtípusokat.
|
///Indításnál betölti a szükséges betűtípusokat.
|
||||||
void openFonts() {
|
void openFonts() {
|
||||||
SDL_EnableUNICODE(1);
|
if(!TTF_WasInit()) TTF_Init();
|
||||||
TTF_Init();
|
|
||||||
fontSmaller = TTF_OpenFont("resources/Roboto-Thin.ttf", 40);
|
float scale = (float) screen -> h / designHeight;
|
||||||
fontSmall = TTF_OpenFont("resources/Roboto-Thin.ttf", 48);
|
fontSmaller = TTF_OpenFont("resources/Roboto-Thin.ttf", larger(1, (int)(40 * scale)));
|
||||||
fontSmallBold = TTF_OpenFont("resources/Roboto-Light.ttf", 53);
|
fontSmall = TTF_OpenFont("resources/Roboto-Thin.ttf", larger(1, (int)(48 * scale)));
|
||||||
fontLarge = TTF_OpenFont("resources/Roboto-Thin.ttf", 120);
|
fontSmallBold = TTF_OpenFont("resources/Roboto-Light.ttf", larger(1, (int)(53 * scale)));
|
||||||
|
fontLarge = TTF_OpenFont("resources/Roboto-Thin.ttf", larger(1, (int)(120 * scale)));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Ha már nem kellenek, felszabadítja a betűtípusokat.
|
///Ha már nem kellenek, felszabadítja a betűtípusokat.
|
||||||
|
|
@ -20,10 +21,10 @@ void freeFonts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
///Itt tárolom a használható karaktereket. Eldönti, hogy a bemenet köztük van-e.
|
///Itt tárolom a használható karaktereket. Eldönti, hogy a bemenet köztük van-e.
|
||||||
bool isValidChar(Uint16 chr) {
|
bool isValidChar(wchar_t chr) {
|
||||||
if(('A' <= chr && chr <= 'Z') || ('a' <= chr && chr <= 'z') || ('0' <= chr && chr <= '9')) return true;
|
if(('A' <= chr && chr <= 'Z') || ('a' <= chr && chr <= 'z') || ('0' <= chr && chr <= '9')) return true;
|
||||||
|
|
||||||
Uint16 validChars[] = L"öüóőúéáűíÖÜÓŐÚÉÁŰÍ|€ß$Łł¤<>#&@{}Đ[]đ+!%=×)(.- ";
|
wchar_t validChars[] = L"öüóőúéáűíÖÜÓŐÚÉÁŰÍ|€ß$Łł¤<>#&@{}Đ[]đ+!%=×)(.- ";
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; validChars[i] != 0; i++) if(chr == validChars[i])
|
for(i = 0; validChars[i] != 0; i++) if(chr == validChars[i])
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -57,14 +58,14 @@ Sint16 percentageToPx(int percentage, bool isWidth) {
|
||||||
* \param string vége
|
* \param string vége
|
||||||
* \return string konkatenált
|
* \return string konkatenált
|
||||||
*/
|
*/
|
||||||
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]) {
|
wchar_t* concatUnicode(const wchar_t a[], const wchar_t b[]) {
|
||||||
int aLength, bLength;
|
int aLength, bLength;
|
||||||
for(aLength = 0; a[aLength] != 0; aLength++)
|
for(aLength = 0; a[aLength] != 0; aLength++)
|
||||||
;
|
;
|
||||||
for(bLength = 0; b[bLength] != 0; bLength++)
|
for(bLength = 0; b[bLength] != 0; bLength++)
|
||||||
;
|
;
|
||||||
|
|
||||||
Uint16* newStr = (Uint16*) malloc((aLength + bLength - 1 + 100) * sizeof(Uint16));
|
wchar_t* newStr = (wchar_t*) malloc((aLength + bLength - 1 + 100) * sizeof(wchar_t));
|
||||||
int i = 0, ai, bi;
|
int i = 0, ai, bi;
|
||||||
for(ai = 0; ai < aLength; ai++)
|
for(ai = 0; ai < aLength; ai++)
|
||||||
newStr[i++] = a[ai];
|
newStr[i++] = a[ai];
|
||||||
|
|
@ -76,9 +77,79 @@ Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
///A megjelenítendő szöveg közepét kell megadni x,y-ként. A szöveget Uint16*-ban, a betűtipust pedig a betűtipus enumból. Ugyan mindent x = 50-nel hívunk meg, ez később változhat, ezért hagyom meg paraméternek.
|
///A megjelenítendő szöveg közepét kell megadni x,y-ként. A szöveget Uint16*-ban, a betűtipust pedig a betűtipus enumból. Ugyan mindent x = 50-nel hívunk meg, ez később változhat, ezért hagyom meg paraméternek.
|
||||||
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType) {
|
void unicodePrintCentered(wchar_t textToWrite[], int x, int y, fontType fontType) {
|
||||||
|
char utf8[2048];
|
||||||
|
wideToUtf8(textToWrite, utf8, sizeof(utf8));
|
||||||
|
utf8PrintCentered(utf8, x, y, fontType);
|
||||||
|
}
|
||||||
|
|
||||||
|
///Ugyanaz, mint az unicodePrintCentered, csak utf-8-as bemenettel.
|
||||||
|
void utf8PrintCentered(const char* textToWrite, int x, int y, fontType fontType) {
|
||||||
|
if(!isRenderingEnabled()) return;
|
||||||
|
|
||||||
TTF_Font* currentFont = selectFont(fontType);
|
TTF_Font* currentFont = selectFont(fontType);
|
||||||
SDL_FreeSurface(text);
|
SDL_FreeSurface(text);
|
||||||
text = TTF_RenderUNICODE_Blended(currentFont, textToWrite, (SDL_Color) {255, 255, 255});
|
text = TTF_RenderUTF8_Blended(currentFont, textToWrite, (SDL_Color) {255, 255, 255});
|
||||||
|
if(text == NULL) return;
|
||||||
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){percentageToPx(x, true) - text -> w / 2, percentageToPx(y, false) - text -> h / 2, 0, 0});
|
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){percentageToPx(x, true) - text -> w / 2, percentageToPx(y, false) - text -> h / 2, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wideToUtf8(const wchar_t* source, char* destination, int destinationSize) {
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
for(; *source != 0; source++) {
|
||||||
|
unsigned int c = (unsigned int) *source;
|
||||||
|
int needed = c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
|
||||||
|
if(written + needed >= destinationSize) break;
|
||||||
|
|
||||||
|
switch(needed) {
|
||||||
|
case 1:
|
||||||
|
destination[written++] = c;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
destination[written++] = 0xC0 | (c >> 6);
|
||||||
|
destination[written++] = 0x80 | (c & 0x3F);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
destination[written++] = 0xE0 | (c >> 12);
|
||||||
|
destination[written++] = 0x80 | ((c >> 6) & 0x3F);
|
||||||
|
destination[written++] = 0x80 | (c & 0x3F);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
destination[written++] = 0xF0 | (c >> 18);
|
||||||
|
destination[written++] = 0x80 | ((c >> 12) & 0x3F);
|
||||||
|
destination[written++] = 0x80 | ((c >> 6) & 0x3F);
|
||||||
|
destination[written++] = 0x80 | (c & 0x3F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destination[written] = 0;
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
int utf8ToWide(const char* source, wchar_t* destination, int destinationSize) {
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
while(*source != 0 && written < destinationSize - 1) {
|
||||||
|
unsigned char lead = (unsigned char) *source++;
|
||||||
|
unsigned int c;
|
||||||
|
int continuations;
|
||||||
|
|
||||||
|
if(lead < 0x80) { c = lead; continuations = 0; }
|
||||||
|
else if((lead & 0xE0) == 0xC0) { c = lead & 0x1F; continuations = 1; }
|
||||||
|
else if((lead & 0xF0) == 0xE0) { c = lead & 0x0F; continuations = 2; }
|
||||||
|
else if((lead & 0xF8) == 0xF0) { c = lead & 0x07; continuations = 3; }
|
||||||
|
else continue;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < continuations; i++) {
|
||||||
|
if((*source & 0xC0) != 0x80) break;
|
||||||
|
c = (c << 6) | (*source++ & 0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
destination[written++] = (wchar_t) c;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination[written] = 0;
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,11 @@
|
||||||
|
|
||||||
void openFonts();
|
void openFonts();
|
||||||
void freeFonts();
|
void freeFonts();
|
||||||
bool isValidChar(Uint16 chr);
|
bool isValidChar(wchar_t chr);
|
||||||
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]);
|
wchar_t* concatUnicode(const wchar_t a[], const wchar_t b[]);
|
||||||
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType);
|
void unicodePrintCentered(wchar_t textToWrite[], int x, int y, fontType fontType);
|
||||||
|
void utf8PrintCentered(const char* textToWrite, int x, int y, fontType fontType);
|
||||||
|
int wideToUtf8(const wchar_t* source, char* destination, int destinationSize);
|
||||||
|
int utf8ToWide(const char* source, wchar_t* destination, int destinationSize);
|
||||||
|
|
||||||
#endif // UNICODEPRINT_H_INCLUDED
|
#endif // UNICODEPRINT_H_INCLUDED
|
||||||
|
|
|
||||||
|
|
@ -1,326 +1,331 @@
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
|
||||||
#define focalLength 0.05 /**< gyújtótáv [m] */
|
#define focalLength 0.05 /**< gyújtótáv [m] */
|
||||||
#define sensorSize 0.07 /**< szenzor hosszabb oldalának a fele [m] */
|
#define sensorSize 0.07 /**< szenzor hosszabb oldalának a fele [m] */
|
||||||
#define renderObjectsPerCube 10 /**< max( (projectile + player + enemy) / m^3), erről később bővebben. */
|
#define renderObjectsPerCube 10 /**< max( (projectile + player + enemy) / m^3), erről később bővebben. */
|
||||||
|
|
||||||
vector3D cameraPosition; /**< A kamera térbeli helyvektora. */
|
vector3D cameraPosition; /**< A kamera térbeli helyvektora. */
|
||||||
float magnification, columns, rows; /**< Ennyi látszik a pályából [m]. */
|
float magnification, columns, rows; /**< Ennyi látszik a pályából [m]. */
|
||||||
bool watchBounds = false; /**< Feldarabolós rajzolás van-e? */
|
bool watchBounds = false; /**< Feldarabolós rajzolás van-e? */
|
||||||
float leftBound, rightBound, upperBound, lowerBound; /**< Darabolás határai. */
|
float leftBound, rightBound, upperBound, lowerBound; /**< Darabolás határai. */
|
||||||
int leftMostBound, rightMostBound, topBound, bottomBound;
|
int leftMostBound, rightMostBound, topBound, bottomBound;
|
||||||
renderObject*** renderMap = NULL; /**< Darabolás mátrixa. */
|
renderObject*** renderMap = NULL; /**< Darabolás mátrixa. */
|
||||||
|
|
||||||
|
|
||||||
///A feldarabolós rajzoláshoz szükséges mátrixot szabadítja fel.
|
///A feldarabolós rajzoláshoz szükséges mátrixot szabadítja fel.
|
||||||
void freeRenderMap() {
|
void freeRenderMap() {
|
||||||
if(renderMap != NULL) {
|
if(renderMap != NULL) {
|
||||||
free(renderMap[0][0]);
|
free(renderMap[0][0]);
|
||||||
free(renderMap[0]);
|
free(renderMap[0]);
|
||||||
free(renderMap);
|
free(renderMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///A feldarabolós rajzoláshoz szükséges mátrixot mallocolja.
|
///A feldarabolós rajzoláshoz szükséges mátrixot mallocolja.
|
||||||
static void initRenderMap() {
|
static void initRenderMap() {
|
||||||
renderMap = (renderObject***) malloc(sizeof(renderObject**));
|
renderMap = (renderObject***) malloc(sizeof(renderObject**));
|
||||||
renderMap[0] = (renderObject**) malloc(sizeof(renderObject*));
|
renderMap[0] = (renderObject**) malloc(sizeof(renderObject*));
|
||||||
renderMap[0][0] = (renderObject*) malloc(sizeof(renderObject));
|
renderMap[0][0] = (renderObject*) malloc(sizeof(renderObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Kiszámolja a kamera poziciója és a képernyő mérete alapján, hogy mennyi látszik a pályából.
|
/** \brief Kiszámolja a kamera poziciója és a képernyő mérete alapján, hogy mennyi látszik a pályából.
|
||||||
*
|
*
|
||||||
* Elsősorban ezeket a változókat változtatja:
|
* Elsősorban ezeket a változókat változtatja:
|
||||||
* columns, rows = képernyőn megjelenő oszlopok és sorok száma,
|
* columns, rows = képernyőn megjelenő oszlopok és sorok száma,
|
||||||
* magnification = megmondja egy méter a kamera "szenzorán" hány pixelnek felel meg (jó soknak)
|
* magnification = megmondja egy méter a kamera "szenzorán" hány pixelnek felel meg (jó soknak)
|
||||||
*
|
*
|
||||||
* Hasonló háromszögek alapján kiszámolja mennyi látszik a pályából:
|
* Hasonló háromszögek alapján kiszámolja mennyi látszik a pályából:
|
||||||
* sensor size
|
* sensor size
|
||||||
* |
|
* |
|
||||||
* V
|
* V
|
||||||
* ----
|
* ----
|
||||||
* \ |
|
* \ |
|
||||||
* \ | <- focalLength
|
* \ | <- focalLength
|
||||||
* \|
|
* \|
|
||||||
* |
|
* |
|
||||||
* |\
|
* |\
|
||||||
* | \
|
* | \
|
||||||
* Z -> | \
|
* Z -> | \
|
||||||
* | \
|
* | \
|
||||||
* | \
|
* | \
|
||||||
* -------------
|
* -------------
|
||||||
* columns
|
* columns
|
||||||
*
|
*
|
||||||
* Ezek alapján reallocolja a darabolós mátrixot.
|
* Ezek alapján reallocolja a darabolós mátrixot.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void calculateRowsAndColumns() {
|
static void calculateRowsAndColumns() {
|
||||||
magnification = (float) screen -> w / 2 / sensorSize;
|
magnification = (float) screen -> w / 2 / sensorSize;
|
||||||
columns = 2 * cameraPosition.z * sensorSize / focalLength;
|
columns = 2 * cameraPosition.z * sensorSize / focalLength;
|
||||||
//hogy a négyzet négyzet is maradjon
|
//hogy a négyzet négyzet is maradjon
|
||||||
rows = (float)screen -> h / screen -> w * columns;
|
rows = (float)screen -> h / screen -> w * columns;
|
||||||
|
|
||||||
if(renderMap == NULL) initRenderMap();
|
if(renderMap == NULL) initRenderMap();
|
||||||
|
|
||||||
int xSize = (int)columns + 4; //a nagyobb testek átlóghatnak a képernyő határán
|
int xSize = (int)columns + 4; //a nagyobb testek átlóghatnak a képernyő határán
|
||||||
int ySize = (int)rows + 4;
|
int ySize = (int)rows + 4;
|
||||||
int iSize = renderObjectsPerCube;
|
int iSize = renderObjectsPerCube;
|
||||||
|
|
||||||
renderObject* innerTmp = (renderObject*) realloc(renderMap[0][0], xSize * ySize * iSize * sizeof(renderObject));
|
renderObject* innerTmp = (renderObject*) realloc(renderMap[0][0], xSize * ySize * iSize * sizeof(renderObject));
|
||||||
renderObject** outerTmp = (renderObject**) realloc(renderMap[0], xSize * ySize * sizeof(renderObject*));
|
renderObject** outerTmp = (renderObject**) realloc(renderMap[0], xSize * ySize * sizeof(renderObject*));
|
||||||
renderMap = (renderObject***) realloc(renderMap, xSize * sizeof(renderObject**));
|
renderMap = (renderObject***) realloc(renderMap, xSize * sizeof(renderObject**));
|
||||||
|
|
||||||
renderMap[0] = outerTmp;
|
renderMap[0] = outerTmp;
|
||||||
|
|
||||||
int x;
|
int x;
|
||||||
for(x = 1; x < xSize; x++)
|
for(x = 1; x < xSize; x++)
|
||||||
renderMap[x] = renderMap[0] + x * ySize;
|
renderMap[x] = renderMap[0] + x * ySize;
|
||||||
|
|
||||||
renderMap[0][0] = innerTmp;
|
renderMap[0][0] = innerTmp;
|
||||||
|
|
||||||
renderObject empty;
|
renderObject empty;
|
||||||
empty.doesExist = false;
|
empty.doesExist = false;
|
||||||
|
|
||||||
int y, i = 0;
|
int y, i = 0;
|
||||||
int j;
|
int j;
|
||||||
for(x = 0; x < xSize; x++)
|
for(x = 0; x < xSize; x++)
|
||||||
for(y = 0; y < ySize; y++) {
|
for(y = 0; y < ySize; y++) {
|
||||||
renderMap[x][y] = renderMap[0][0] + i++ * iSize;
|
renderMap[x][y] = renderMap[0][0] + i++ * iSize;
|
||||||
for(j = 0; j < iSize; j++) renderMap[x][y][j] = empty;
|
for(j = 0; j < iSize; j++) renderMap[x][y][j] = empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///A játékost követi a kamerával, nem hagyja, hogy a pálya alá lásson.
|
///A képernyő méretének változása után újraszámolja a látható területet és átméretezi a darabolós mátrixot.
|
||||||
void followPlayerWithCamera() {
|
void refreshCameraForScreen() {
|
||||||
renderObject player = getPlayerRenderObject();
|
calculateRowsAndColumns();
|
||||||
cameraPosition.x = (2 * player.position.x + player.size.x) / 2;
|
}
|
||||||
cameraPosition.y = (player.position.y < rows / 2 ? rows / 2 : player.position.y) + 1;
|
|
||||||
}
|
///A játékost követi a kamerával, nem hagyja, hogy a pálya alá lásson.
|
||||||
|
void followPlayerWithCamera() {
|
||||||
///A menüben használt kamerát állítja be, visszaadja a columns-t és rows-t is.
|
renderObject player = getPlayerRenderObject();
|
||||||
void menuCamera(int* getColumns, int* getRows) {
|
cameraPosition.x = (2 * player.position.x + player.size.x) / 2;
|
||||||
cameraPosition.z = cameraDeltaZDistanceStart;
|
cameraPosition.y = (player.position.y < rows / 2 ? rows / 2 : player.position.y) + 1;
|
||||||
calculateRowsAndColumns();
|
}
|
||||||
*getColumns = columns;
|
|
||||||
*getRows = rows;
|
///A menüben használt kamerát állítja be, visszaadja a columns-t és rows-t is.
|
||||||
cameraPosition.x = columns / 2;
|
void menuCamera(int* getColumns, int* getRows) {
|
||||||
cameraPosition.y = rows / 2;
|
cameraPosition.z = cameraDeltaZDistanceStart;
|
||||||
}
|
calculateRowsAndColumns();
|
||||||
|
*getColumns = columns;
|
||||||
///Visszaadja, hogy hány oszlop látszik a pályából.
|
*getRows = rows;
|
||||||
int getColumns() {
|
cameraPosition.x = columns / 2;
|
||||||
return columns;
|
cameraPosition.y = rows / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief A kamera dollyzását végzi, a kamerát mozgatja
|
///Visszaadja, hogy hány oszlop látszik a pályából.
|
||||||
* A dolly állását staticban tárolja, ezért új dolly eseteén először egy restart = true-val kell meghívni,
|
int getColumns() {
|
||||||
* \param ms eltelt idő
|
return columns;
|
||||||
* \param kell-e újrakezdés?
|
}
|
||||||
* \return elérte-e a végállást?
|
|
||||||
* Minden frameban újraszámolja a rows&coulmns-t,
|
/** \brief A kamera dollyzását végzi, a kamerát mozgatja
|
||||||
*/
|
* A dolly állását staticban tárolja, ezért új dolly eseteén először egy restart = true-val kell meghívni,
|
||||||
bool cameraDollyZ(int deltaTime, bool restart) {
|
* \param ms eltelt idő
|
||||||
static int timePassed;
|
* \param kell-e újrakezdés?
|
||||||
if(restart) timePassed = 0;
|
* \return elérte-e a végállást?
|
||||||
|
* Minden frameban újraszámolja a rows&coulmns-t,
|
||||||
bool done = true;
|
*/
|
||||||
|
bool cameraDollyZ(int deltaTime, bool restart) {
|
||||||
timePassed += deltaTime;
|
static int timePassed;
|
||||||
|
if(restart) timePassed = 0;
|
||||||
float t = (float)(cameraDollyTime - timePassed) / cameraDollyTime;
|
|
||||||
float cube = t*t*t;
|
bool done = true;
|
||||||
|
|
||||||
float currentZ = cameraDeltaZDistanceEnd + (cameraDeltaZDistanceStart - cameraDeltaZDistanceEnd) * cube;
|
timePassed += deltaTime;
|
||||||
|
|
||||||
if(currentZ <= cameraDeltaZDistanceEnd) {
|
float t = (float)(cameraDollyTime - timePassed) / cameraDollyTime;
|
||||||
currentZ = cameraDeltaZDistanceEnd;
|
float cube = t*t*t;
|
||||||
done = false;
|
|
||||||
}
|
float currentZ = cameraDeltaZDistanceEnd + (cameraDeltaZDistanceStart - cameraDeltaZDistanceEnd) * cube;
|
||||||
|
|
||||||
cameraPosition.z = currentZ;
|
if(currentZ <= cameraDeltaZDistanceEnd) {
|
||||||
calculateRowsAndColumns();
|
currentZ = cameraDeltaZDistanceEnd;
|
||||||
return done;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Térbeli pontból síkbelit képez.
|
cameraPosition.z = currentZ;
|
||||||
* A 3D-s pont koordinátái és a kamera alapján kiszámolja, hogy a kamera 2D-s szenzorán hol jelenik meg a pont.
|
calculateRowsAndColumns();
|
||||||
* Geometriailag leírva, a két ponton (point, cameraPosition) átmenő egyenes egyenletének, és a 'szenzor' vízszintesének metszéspontja
|
return done;
|
||||||
* a keresett pontunk. A lent és a linken is látható egyenletet először a tér x-z, majd az y-z vetületére alkalmazzuk,
|
}
|
||||||
* és megkapjuk a térbeli pontunk megfelelő síkbeli leképezést.
|
|
||||||
* Ez interaktívan ábrázolva így néz ki: https://www.desmos.com/calculator/8qjvkptjmn
|
/** \brief Térbeli pontból síkbelit képez.
|
||||||
* \param Térvektor típusú pont
|
* A 3D-s pont koordinátái és a kamera alapján kiszámolja, hogy a kamera 2D-s szenzorán hol jelenik meg a pont.
|
||||||
* \return Síkvektor típusú pont
|
* Geometriailag leírva, a két ponton (point, cameraPosition) átmenő egyenes egyenletének, és a 'szenzor' vízszintesének metszéspontja
|
||||||
* A visszaadott pontnak int koordinátái vannak, hiszen valamelyik pixel koordinátáit jelöli.
|
* a keresett pontunk. A lent és a linken is látható egyenletet először a tér x-z, majd az y-z vetületére alkalmazzuk,
|
||||||
* Ez a függvény igazából egy camera obscura modellje.
|
* és megkapjuk a térbeli pontunk megfelelő síkbeli leképezést.
|
||||||
*/
|
* Ez interaktívan ábrázolva így néz ki: https://www.desmos.com/calculator/8qjvkptjmn
|
||||||
intVector2D get2DPoint(vector3D point) {
|
* \param Térvektor típusú pont
|
||||||
//Ha watchBounds = true, csak egy megadott kockán belül adja vissza az értéket (rajzol), ez a feldarabolás miatt fontos
|
* \return Síkvektor típusú pont
|
||||||
if(watchBounds) {
|
* A visszaadott pontnak int koordinátái vannak, hiszen valamelyik pixel koordinátáit jelöli.
|
||||||
putInsideIntervalF(leftBound, &point.x, rightBound);
|
* Ez a függvény igazából egy camera obscura modellje.
|
||||||
putInsideIntervalF(lowerBound, &point.y, upperBound);
|
*/
|
||||||
}
|
intVector2D get2DPoint(vector3D point) {
|
||||||
|
//Ha watchBounds = true, csak egy megadott kockán belül adja vissza az értéket (rajzol), ez a feldarabolás miatt fontos
|
||||||
//Ezt a két kifejezést újra felhasználjuk
|
if(watchBounds) {
|
||||||
float zDist = point.z - cameraPosition.z;
|
putInsideIntervalF(leftBound, &point.x, rightBound);
|
||||||
float zDistFromHole = zDist - focalLength;
|
putInsideIntervalF(lowerBound, &point.y, upperBound);
|
||||||
float dx = (cameraPosition.x * zDistFromHole + focalLength * point.x) / zDist - cameraPosition.x;
|
}
|
||||||
float dy = (cameraPosition.y * zDistFromHole + focalLength * point.y) / zDist - cameraPosition.y;
|
|
||||||
|
//Ezt a két kifejezést újra felhasználjuk
|
||||||
//Megfelelően tükrözzük a kapot pontot, és a méterben kapott értéket átváltjuk pixelekre
|
float zDist = point.z - cameraPosition.z;
|
||||||
intVector2D resultPoint = {
|
float zDistFromHole = zDist - focalLength;
|
||||||
(int)(screen -> w / 2 - magnification * dx),
|
float dx = (cameraPosition.x * zDistFromHole + focalLength * point.x) / zDist - cameraPosition.x;
|
||||||
(int)(screen -> h / 2 + magnification * dy)
|
float dy = (cameraPosition.y * zDistFromHole + focalLength * point.y) / zDist - cameraPosition.y;
|
||||||
};
|
|
||||||
|
//Megfelelően tükrözzük a kapot pontot, és a méterben kapott értéket átváltjuk pixelekre
|
||||||
return resultPoint;
|
intVector2D resultPoint = {
|
||||||
}
|
(int)(screen -> w / 2 - magnification * dx),
|
||||||
|
(int)(screen -> h / 2 + magnification * dy)
|
||||||
/** \brief Lerajzol egy négyszöget
|
};
|
||||||
* A bemenetként kapott 4 pont alkotta négyszöget rajzolja ki.
|
|
||||||
* \param síkvektor a csúcshoz
|
return resultPoint;
|
||||||
* \param síkvektor b csúcshoz
|
}
|
||||||
* \param síkvektor c csúcshoz
|
|
||||||
* \param síkvektor d csúcshoz
|
/** \brief Lerajzol egy négyszöget
|
||||||
* \param szín négyszög színe
|
* A bemenetként kapott 4 pont alkotta négyszöget rajzolja ki.
|
||||||
* Ezt egyszer kitöltéssel csinálja, egyszer pedig anti-aliasing poligonnal,
|
* \param síkvektor a csúcshoz
|
||||||
* hogy a rajz széle ne legyen recegős.
|
* \param síkvektor b csúcshoz
|
||||||
*/
|
* \param síkvektor c csúcshoz
|
||||||
static void drawTetragon(intVector2D a, intVector2D b, intVector2D c, intVector2D d, color color) {
|
* \param síkvektor d csúcshoz
|
||||||
Sint16 xCoords[4] = {(Sint16)a.x, (Sint16)b.x, (Sint16)c.x, (Sint16)d.x};
|
* \param szín négyszög színe
|
||||||
Sint16 yCoords[4] = {(Sint16)a.y, (Sint16)b.y, (Sint16)c.y, (Sint16)d.y};
|
* Ezt egyszer kitöltéssel csinálja, egyszer pedig anti-aliasing poligonnal,
|
||||||
|
* hogy a rajz széle ne legyen recegős.
|
||||||
filledPolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
|
*/
|
||||||
aapolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
|
static void drawTetragon(intVector2D a, intVector2D b, intVector2D c, intVector2D d, color color) {
|
||||||
}
|
Sint16 xCoords[4] = {(Sint16)a.x, (Sint16)b.x, (Sint16)c.x, (Sint16)d.x};
|
||||||
|
Sint16 yCoords[4] = {(Sint16)a.y, (Sint16)b.y, (Sint16)c.y, (Sint16)d.y};
|
||||||
/** \brief Lerajzol egy téglatestet
|
|
||||||
* A kamera modul lényege, a rajzolást végzi el az eddigi függvények segítségével.
|
filledPolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
|
||||||
* \param test téglatest adatai
|
aapolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
|
||||||
* \param bool melyik oldalakat kell rajzolni?
|
}
|
||||||
* Végez egy plusz ellenőrést is, nem csak a paraméterben megadott tömb alapján nem rajzol oldalakat,
|
|
||||||
* azokat se rajzolja le, amiket a helyzetük miatt biztosan nem láthat a kamera.
|
/** \brief Lerajzol egy téglatestet
|
||||||
*/
|
* A kamera modul lényege, a rajzolást végzi el az eddigi függvények segítségével.
|
||||||
void drawCuboid(renderObject object, bool sides[]) {
|
* \param test téglatest adatai
|
||||||
intVector2D vertexes[8];
|
* \param bool melyik oldalakat kell rajzolni?
|
||||||
//A téglatestet bejárva megkeressük a csúcsait
|
* Végez egy plusz ellenőrést is, nem csak a paraméterben megadott tömb alapján nem rajzol oldalakat,
|
||||||
int i;
|
* azokat se rajzolja le, amiket a helyzetük miatt biztosan nem láthat a kamera.
|
||||||
for(i = 0; i < 8; i++) {
|
*/
|
||||||
vertexes[i] = get2DPoint(object.position);
|
void drawCuboid(renderObject object, bool sides[]) {
|
||||||
switch(i % 4) {
|
intVector2D vertexes[8];
|
||||||
case 0:
|
//A téglatestet bejárva megkeressük a csúcsait
|
||||||
object.position.x += object.size.x;
|
int i;
|
||||||
break;
|
for(i = 0; i < 8; i++) {
|
||||||
case 1:
|
vertexes[i] = get2DPoint(object.position);
|
||||||
object.position.y += object.size.y;
|
switch(i % 4) {
|
||||||
break;
|
case 0:
|
||||||
case 2:
|
object.position.x += object.size.x;
|
||||||
object.position.x -= object.size.x;
|
break;
|
||||||
break;
|
case 1:
|
||||||
case 3:
|
object.position.y += object.size.y;
|
||||||
object.position.y -= object.size.y;
|
break;
|
||||||
}
|
case 2:
|
||||||
if(i == 3) object.position.z += object.size.z;
|
object.position.x -= object.size.x;
|
||||||
}
|
break;
|
||||||
|
case 3:
|
||||||
//alja
|
object.position.y -= object.size.y;
|
||||||
if(sides[0] && object.position.y > cameraPosition.y) drawTetragon(vertexes[0], vertexes[4], vertexes[5], vertexes[1], object.colors.dark);
|
}
|
||||||
//bal oldali lap
|
if(i == 3) object.position.z += object.size.z;
|
||||||
if(sides[1] && object.position.x > cameraPosition.x) drawTetragon(vertexes[0], vertexes[3], vertexes[7], vertexes[4], object.colors.dark);
|
}
|
||||||
//jobb oldali lap
|
|
||||||
if(sides[2] && object.position.x + object.size.x < cameraPosition.x) drawTetragon(vertexes[1], vertexes[2], vertexes[6], vertexes[5], object.colors.dark);
|
//alja
|
||||||
//teteje
|
if(sides[0] && object.position.y > cameraPosition.y) drawTetragon(vertexes[0], vertexes[4], vertexes[5], vertexes[1], object.colors.dark);
|
||||||
if(sides[3] && object.position.y + object.size.y < cameraPosition.y) drawTetragon(vertexes[3], vertexes[7], vertexes[6], vertexes[2], object.colors.light);
|
//bal oldali lap
|
||||||
//eleje
|
if(sides[1] && object.position.x > cameraPosition.x) drawTetragon(vertexes[0], vertexes[3], vertexes[7], vertexes[4], object.colors.dark);
|
||||||
if(sides[4]) drawTetragon(vertexes[4], vertexes[5], vertexes[6], vertexes[7], object.colors.normal);
|
//jobb oldali lap
|
||||||
}
|
if(sides[2] && object.position.x + object.size.x < cameraPosition.x) drawTetragon(vertexes[1], vertexes[2], vertexes[6], vertexes[5], object.colors.dark);
|
||||||
|
//teteje
|
||||||
/// Az egy m^3-ben lévő testeket rajzolja le
|
if(sides[3] && object.position.y + object.size.y < cameraPosition.y) drawTetragon(vertexes[3], vertexes[7], vertexes[6], vertexes[2], object.colors.light);
|
||||||
static void drawPlace(int x, int* y, int direction, int bound) {
|
//eleje
|
||||||
bool sides[5] = {true, true, true, true, true};
|
if(sides[4]) drawTetragon(vertexes[4], vertexes[5], vertexes[6], vertexes[7], object.colors.normal);
|
||||||
|
}
|
||||||
renderObject toDraw = getBlockRenderObject(x, y, direction, bound, sides);
|
|
||||||
if(toDraw.doesExist) {
|
/// Az egy m^3-ben lévő testeket rajzolja le
|
||||||
watchBounds = false;
|
static void drawPlace(int x, int* y, int direction, int bound) {
|
||||||
drawCuboid(toDraw, sides);
|
bool sides[5] = {true, true, true, true, true};
|
||||||
watchBounds = true;
|
|
||||||
}
|
renderObject toDraw = getBlockRenderObject(x, y, direction, bound, sides);
|
||||||
else {
|
if(toDraw.doesExist) {
|
||||||
int i = 0;
|
watchBounds = false;
|
||||||
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
|
drawCuboid(toDraw, sides);
|
||||||
while(toDraw.doesExist && i < renderObjectsPerCube) {
|
watchBounds = true;
|
||||||
drawCuboid(toDraw, sides);
|
}
|
||||||
i++;
|
else {
|
||||||
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
|
int i = 0;
|
||||||
}
|
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
|
||||||
|
while(toDraw.doesExist && i < renderObjectsPerCube) {
|
||||||
renderObject player = getPlayerRenderObject();
|
drawCuboid(toDraw, sides);
|
||||||
|
i++;
|
||||||
if(
|
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
|
||||||
(x == (int)floor(player.position.x) || x == (int)floor(player.position.x + player.size.x)) &&
|
}
|
||||||
(*y == (int)floor(player.position.y) || *y == (int)floor(player.position.y + player.size.y))
|
|
||||||
)
|
renderObject player = getPlayerRenderObject();
|
||||||
drawCuboid(player, sides);
|
|
||||||
}
|
if(
|
||||||
}
|
(x == (int)floor(player.position.x) || x == (int)floor(player.position.x + player.size.x)) &&
|
||||||
|
(*y == (int)floor(player.position.y) || *y == (int)floor(player.position.y + player.size.y))
|
||||||
///Az egy oszlopban lévő testeket rajzolja le, a részecskéket mozgatja közvetlen
|
)
|
||||||
static void drawY(int deltaTime, int x) {
|
drawCuboid(player, sides);
|
||||||
int y;
|
}
|
||||||
|
}
|
||||||
for(y = topBound; y > cameraPosition.y; y--) {
|
|
||||||
upperBound = y + 1;
|
///Az egy oszlopban lévő testeket rajzolja le, a részecskéket mozgatja közvetlen
|
||||||
lowerBound = y;
|
static void drawY(int deltaTime, int x) {
|
||||||
drawPlace(x, &y, -1, (int)cameraPosition.y);
|
int y;
|
||||||
}
|
|
||||||
for(y = bottomBound; y <= cameraPosition.y; y++) {
|
for(y = topBound; y > cameraPosition.y; y--) {
|
||||||
upperBound = y + 1;
|
upperBound = y + 1;
|
||||||
lowerBound = y;
|
lowerBound = y;
|
||||||
drawPlace(x, &y, 1, (int)cameraPosition.y + 1);
|
drawPlace(x, &y, -1, (int)cameraPosition.y);
|
||||||
}
|
}
|
||||||
watchBounds = false;
|
for(y = bottomBound; y <= cameraPosition.y; y++) {
|
||||||
drawParticles(x, bottomBound, topBound, deltaTime);
|
upperBound = y + 1;
|
||||||
watchBounds = true;
|
lowerBound = y;
|
||||||
}
|
drawPlace(x, &y, 1, (int)cameraPosition.y + 1);
|
||||||
|
}
|
||||||
/** \brief Lerajzolja a teljes látható játékteret.
|
watchBounds = false;
|
||||||
* A megfelelő rajzoláshoz figyelni kell a testek takarására, nem mindegy ezért, hogy milyen sorrendben rajzoljuk őket.
|
drawParticles(x, bottomBound, topBound, deltaTime);
|
||||||
* A részecskéknél ezzel nincs probléma, azokat bármilyen sorrendben rajzolhatjuk. Ők a játékteret kitakarják, egymásnál viszont nem látszik,
|
watchBounds = true;
|
||||||
* hogy melyik takrja melyiket, ezért azokat elég a játéktér után bármilyen sorrendben lerajzolni.
|
}
|
||||||
* A térképet alkotó kockáknál már nem ilyen egyszeű a helyzet. Azokat 4 irányból kell rajzolni, bal lentről, jobb lentről, bal fentről, illetve jobb fentről középre.
|
|
||||||
* Ha ebben a négy lépésben rajzoljuk őket (ezek között a sorrend nem számít) akkor mindig a legfesőket rajzoljuk utoljára, és így valósnak néz ki az eredmény.
|
/** \brief Lerajzolja a teljes látható játékteret.
|
||||||
* A játékos, a lövedékek, illetve az ellenségek viszont sajnos nincsenek egy négyzethálóhoz kötve. Így gyakran megesik, hogy az egyik felüket a pálya
|
* A megfelelő rajzoláshoz figyelni kell a testek takarására, nem mindegy ezért, hogy milyen sorrendben rajzoljuk őket.
|
||||||
* egyik kockája előtt, a másikat pedig az után, de még a kövektező előtt kéne rajzolni. Ezt nem tudjuk megcsinálni, hatalmas erőforrásba kerülne ez a majdnem pixelről
|
* A részecskéknél ezzel nincs probléma, azokat bármilyen sorrendben rajzolhatjuk. Ők a játékteret kitakarják, egymásnál viszont nem látszik,
|
||||||
* pixelre történő szkennelés. A pályát továbbra is m^3-ént szeretnénk lerajzolni. Hogy ez megfelelően nézzen ki, minden köbméterben csak az abban a kockában lévő dolgokat
|
* hogy melyik takrja melyiket, ezért azokat elég a játéktér után bármilyen sorrendben lerajzolni.
|
||||||
* szeretnénk megrajzolni. Ehhez fel kell "darabolnunk" a játékost, a lövedékeket, illetve az ellenségeket is. A darabolás azt jelenti, hogy egy mátrix minden cellájába
|
* A térképet alkotó kockáknál már nem ilyen egyszeű a helyzet. Azokat 4 irányból kell rajzolni, bal lentről, jobb lentről, bal fentről, illetve jobb fentről középre.
|
||||||
* beírjuk, hogy az adott kockában melyik, milyen tulajdonsággal rendelkező testek lógnak be. Rajzolásnál pedig a testeknek mindig csak az adott kockabeli részét rajzoljuk le.
|
* Ha ebben a négy lépésben rajzoljuk őket (ezek között a sorrend nem számít) akkor mindig a legfesőket rajzoljuk utoljára, és így valósnak néz ki az eredmény.
|
||||||
* Mivel a kockákat jó sorrendben rajzoljuk, így a bennük levő "testekrészeket" is jó sorrendbe fogjuk rajzolni. A problémát megoldottuk.
|
* A játékos, a lövedékek, illetve az ellenségek viszont sajnos nincsenek egy négyzethálóhoz kötve. Így gyakran megesik, hogy az egyik felüket a pálya
|
||||||
* \param ms eltelt idő
|
* egyik kockája előtt, a másikat pedig az után, de még a kövektező előtt kéne rajzolni. Ezt nem tudjuk megcsinálni, hatalmas erőforrásba kerülne ez a majdnem pixelről
|
||||||
* Ez a függvény elvégzi a részecskék, a pálya, illetve minden más test rajzolását is. A részecskék mozgatása innen van meghívva.
|
* pixelre történő szkennelés. A pályát továbbra is m^3-ént szeretnénk lerajzolni. Hogy ez megfelelően nézzen ki, minden köbméterben csak az abban a kockában lévő dolgokat
|
||||||
*/
|
* szeretnénk megrajzolni. Ehhez fel kell "darabolnunk" a játékost, a lövedékeket, illetve az ellenségeket is. A darabolás azt jelenti, hogy egy mátrix minden cellájába
|
||||||
void drawMap(int deltaTime) {
|
* beírjuk, hogy az adott kockában melyik, milyen tulajdonsággal rendelkező testek lógnak be. Rajzolásnál pedig a testeknek mindig csak az adott kockabeli részét rajzoljuk le.
|
||||||
leftMostBound = (int)(cameraPosition.x - (float)columns / 2) - 1;
|
* Mivel a kockákat jó sorrendben rajzoljuk, így a bennük levő "testekrészeket" is jó sorrendbe fogjuk rajzolni. A problémát megoldottuk.
|
||||||
rightMostBound = (int)(cameraPosition.x + (float)columns / 2) + 1;
|
* \param ms eltelt idő
|
||||||
topBound = (int)(cameraPosition.y + (float)rows / 2 + 1);
|
* Ez a függvény elvégzi a részecskék, a pálya, illetve minden más test rajzolását is. A részecskék mozgatása innen van meghívva.
|
||||||
bottomBound = (int)(cameraPosition.y - (float)rows / 2 - 1);
|
*/
|
||||||
|
void drawMap(int deltaTime) {
|
||||||
int y, x;
|
leftMostBound = (int)(cameraPosition.x - (float)columns / 2) - 1;
|
||||||
|
rightMostBound = (int)(cameraPosition.x + (float)columns / 2) + 1;
|
||||||
for(x = leftMostBound; x < rightMostBound; x++)
|
topBound = (int)(cameraPosition.y + (float)rows / 2 + 1);
|
||||||
for(y = bottomBound; y < topBound; y++)
|
bottomBound = (int)(cameraPosition.y - (float)rows / 2 - 1);
|
||||||
getFloatersRenderObject(x, y, renderMap[x - leftMostBound][y - bottomBound], renderObjectsPerCube);
|
|
||||||
|
int y, x;
|
||||||
float slicer = cameraPosition.x;
|
|
||||||
watchBounds = true;
|
for(x = leftMostBound; x < rightMostBound; x++)
|
||||||
for(x = leftMostBound; x <= slicer; x++) {
|
for(y = bottomBound; y < topBound; y++)
|
||||||
leftBound = x - 0.005;
|
getFloatersRenderObject(x, y, renderMap[x - leftMostBound][y - bottomBound], renderObjectsPerCube);
|
||||||
rightBound = x + 1 + 0.005;
|
|
||||||
drawY(deltaTime, x);
|
float slicer = cameraPosition.x;
|
||||||
}
|
watchBounds = true;
|
||||||
for(x = rightMostBound; x > slicer - 1; x--) {
|
for(x = leftMostBound; x <= slicer; x++) {
|
||||||
leftBound = x - 0.005;
|
leftBound = x - 0.005;
|
||||||
rightBound = x + 1 + 0.005;
|
rightBound = x + 1 + 0.005;
|
||||||
drawY(deltaTime, x);
|
drawY(deltaTime, x);
|
||||||
}
|
}
|
||||||
|
for(x = rightMostBound; x > slicer - 1; x--) {
|
||||||
watchBounds = false;
|
leftBound = x - 0.005;
|
||||||
}
|
rightBound = x + 1 + 0.005;
|
||||||
|
drawY(deltaTime, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchBounds = false;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#define cameraDollyTime 3250 /**<[ms]*/
|
#define cameraDollyTime 3250 /**<[ms]*/
|
||||||
|
|
||||||
void freeRenderMap();
|
void freeRenderMap();
|
||||||
|
void refreshCameraForScreen();
|
||||||
void followPlayerWithCamera();
|
void followPlayerWithCamera();
|
||||||
void menuCamera(int* getColumns, int* getRows);
|
void menuCamera(int* getColumns, int* getRows);
|
||||||
int getColumns();
|
int getColumns();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
#include <SDL_gfxPrimitives.h>
|
#include "auxiliary/gfxPrimitives.h"
|
||||||
|
|
||||||
#include "auxiliary/auxFunctions.h"
|
#include "auxiliary/auxFunctions.h"
|
||||||
|
|
||||||
|
|
@ -15,23 +15,24 @@
|
||||||
#define GLOBAL_H_INCLUDED
|
#define GLOBAL_H_INCLUDED
|
||||||
|
|
||||||
#define FPS (int) 50
|
#define FPS (int) 50
|
||||||
|
#define designHeight 1080 /**< Ehhez a magassághoz vannak méretezve a betűtípusok. */
|
||||||
|
|
||||||
float g;
|
extern float g;
|
||||||
|
|
||||||
///<Globális változók>
|
///<Globális változók>
|
||||||
SDL_Surface* screen;
|
extern SDL_Surface* screen;
|
||||||
TTF_Font* fontSmaller;
|
extern TTF_Font* fontSmaller;
|
||||||
TTF_Font* fontSmall;
|
extern TTF_Font* fontSmall;
|
||||||
TTF_Font* fontSmallBold;
|
extern TTF_Font* fontSmallBold;
|
||||||
TTF_Font* fontLarge;
|
extern TTF_Font* fontLarge;
|
||||||
SDL_Surface* text;
|
extern SDL_Surface* text;
|
||||||
unsigned char* keys;
|
extern unsigned char* keys;
|
||||||
///</Globális változók>
|
///</Globális változók>
|
||||||
|
|
||||||
|
|
||||||
///<Vektorok>
|
///<Vektorok>
|
||||||
typedef struct vector2D {
|
typedef struct vector2D {
|
||||||
//1 egység == 1m
|
//1 egység == 1m
|
||||||
float x, y;
|
float x, y;
|
||||||
} vector2D;
|
} vector2D;
|
||||||
|
|
||||||
|
|
@ -40,13 +41,13 @@ typedef struct intVector2D {
|
||||||
} intVector2D;
|
} intVector2D;
|
||||||
|
|
||||||
typedef struct vector3D {
|
typedef struct vector3D {
|
||||||
//1 egység == 1m
|
//1 egység == 1m
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
} vector3D;
|
} vector3D;
|
||||||
///</Vektorok>
|
///</Vektorok>
|
||||||
|
|
||||||
|
|
||||||
///<Színek>
|
///<Színek>
|
||||||
typedef struct color {
|
typedef struct color {
|
||||||
unsigned char r, g, b, a;
|
unsigned char r, g, b, a;
|
||||||
} color;
|
} color;
|
||||||
|
|
@ -54,7 +55,7 @@ typedef struct color {
|
||||||
typedef struct colors {
|
typedef struct colors {
|
||||||
color light, normal, dark;
|
color light, normal, dark;
|
||||||
} colors;
|
} colors;
|
||||||
///</Színek>
|
///</Színek>
|
||||||
|
|
||||||
|
|
||||||
typedef enum block {
|
typedef enum block {
|
||||||
|
|
|
||||||
14
Forráskód/modules/globals.c
Normal file
14
Forráskód/modules/globals.c
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "global.h"
|
||||||
|
#include "saves.h"
|
||||||
|
|
||||||
|
float g;
|
||||||
|
|
||||||
|
SDL_Surface* screen;
|
||||||
|
TTF_Font* fontSmaller;
|
||||||
|
TTF_Font* fontSmall;
|
||||||
|
TTF_Font* fontSmallBold;
|
||||||
|
TTF_Font* fontLarge;
|
||||||
|
SDL_Surface* text;
|
||||||
|
unsigned char* keys;
|
||||||
|
|
||||||
|
bool existingSaves[maxNOSaves];
|
||||||
|
|
@ -11,13 +11,12 @@ static void drawMenuParticles(int deltaTime) {
|
||||||
|
|
||||||
///A főmenüt rajzolja.
|
///A főmenüt rajzolja.
|
||||||
void drawMainMenu(int deltaTime) {
|
void drawMainMenu(int deltaTime) {
|
||||||
Uint16 menuOptions[][50] = {
|
wchar_t menuOptions[][50] = {
|
||||||
L"Indítás",
|
L"Indítás",
|
||||||
L"Betöltés",
|
L"Betöltés",
|
||||||
L"Beállítások",
|
L"Beállítások",
|
||||||
L"Ranglista",
|
L"Ranglista",
|
||||||
L"Leírás",
|
L"Leírás",
|
||||||
L"Kilépés",
|
|
||||||
L""
|
L""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -37,7 +36,7 @@ static inline void printBack() {
|
||||||
|
|
||||||
///A beállítások menüpont rajzolása, a beállításokat a betöltött mentések is befolyásolják. Figyelni kell, hogy a belépés kattintását ne érzékelje csúszka kattintásnak.
|
///A beállítások menüpont rajzolása, a beállításokat a betöltött mentések is befolyásolják. Figyelni kell, hogy a belépés kattintását ne érzékelje csúszka kattintásnak.
|
||||||
void drawOptionsMenu(int deltaTime, int currentOptions[], bool click) {
|
void drawOptionsMenu(int deltaTime, int currentOptions[], bool click) {
|
||||||
Uint16 optionsMenuOptions[][50] = {
|
wchar_t optionsMenuOptions[][50] = {
|
||||||
L"Világ szélessége",
|
L"Világ szélessége",
|
||||||
L"Világ magassága",
|
L"Világ magassága",
|
||||||
L"Részecskék száma",
|
L"Részecskék száma",
|
||||||
|
|
@ -60,10 +59,10 @@ void drawOptionsMenu(int deltaTime, int currentOptions[], bool click) {
|
||||||
);
|
);
|
||||||
|
|
||||||
filledCircleColor(screen, (float) screen -> w / 100 * (30 + 0.4 * 100 * (float)(currentOptions[i] - minOptions[i]) / (maxOptions[i] - minOptions[i])),
|
filledCircleColor(screen, (float) screen -> w / 100 * (30 + 0.4 * 100 * (float)(currentOptions[i] - minOptions[i]) / (maxOptions[i] - minOptions[i])),
|
||||||
(float) screen -> h / 100 * (optionsStart + i * optionsTav), 20, 0xFFFFFFFF
|
(float) screen -> h / 100 * (optionsStart + i * optionsTav), larger(4, 20 * screen -> h / designHeight), 0xFFFFFFFF
|
||||||
);
|
);
|
||||||
aacircleColor(screen, (float) screen -> w / 100 * (30 + 0.4 * 100 * (float)(currentOptions[i] - minOptions[i]) / (maxOptions[i] - minOptions[i])),
|
aacircleColor(screen, (float) screen -> w / 100 * (30 + 0.4 * 100 * (float)(currentOptions[i] - minOptions[i]) / (maxOptions[i] - minOptions[i])),
|
||||||
(float) screen -> h / 100 * (optionsStart + i * optionsTav), 20, 0xFFFFFFFF
|
(float) screen -> h / 100 * (optionsStart + i * optionsTav), larger(4, 20 * screen -> h / designHeight), 0xFFFFFFFF
|
||||||
);
|
);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|
@ -84,7 +83,7 @@ void drawOptionsMenu(int deltaTime, int currentOptions[], bool click) {
|
||||||
///A játék leírását rajzolja meg.
|
///A játék leírását rajzolja meg.
|
||||||
void drawInfoMenu(int deltaTime) {
|
void drawInfoMenu(int deltaTime) {
|
||||||
|
|
||||||
Uint16 info[][150] = {
|
wchar_t info[][150] = {
|
||||||
L"Ebben a játékban pontokat szerezni és költeni",
|
L"Ebben a játékban pontokat szerezni és költeni",
|
||||||
L"is tudsz. Minden megtalált kék kockáért jár egy pont.",
|
L"is tudsz. Minden megtalált kék kockáért jár egy pont.",
|
||||||
L"Mozogni a WAD billentyűk, szóköz, vagy a nyilak",
|
L"Mozogni a WAD billentyűk, szóköz, vagy a nyilak",
|
||||||
|
|
@ -106,16 +105,16 @@ void drawInfoMenu(int deltaTime) {
|
||||||
drawMenuParticles(deltaTime);
|
drawMenuParticles(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint16 names[topListItemsMax][100];
|
static wchar_t names[topListItemsMax][100];
|
||||||
int points[topListItemsMax];
|
static int points[topListItemsMax];
|
||||||
int namesIndex;
|
static int namesIndex;
|
||||||
|
|
||||||
///Ha megtelt a toplista, rendezi, és az utolsó elemét lecseréli. A ranglista fájlt se kéne nagyon piszkálni a felhasználónak.
|
///Ha megtelt a toplista, rendezi, és az utolsó elemét lecseréli. A ranglista fájlt se kéne nagyon piszkálni a felhasználónak.
|
||||||
static void sortTopList() {
|
static void sortTopList() {
|
||||||
|
|
||||||
int i, j;
|
int i, j;
|
||||||
int tmpInt;
|
int tmpInt;
|
||||||
Uint16 tmpStr[100];
|
wchar_t tmpStr[100];
|
||||||
|
|
||||||
for(i = 0; i < namesIndex; i++) {
|
for(i = 0; i < namesIndex; i++) {
|
||||||
int maxIndex = i;
|
int maxIndex = i;
|
||||||
|
|
@ -140,23 +139,19 @@ void loadTopList() {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(topList != NULL) {
|
if(topList != NULL) {
|
||||||
|
char lineName[400];
|
||||||
namesIndex = 0;
|
namesIndex = 0;
|
||||||
while(true) {
|
while(fscanf(topList, " %399[^,\n],%d", lineName, &points[namesIndex]) == 2) {
|
||||||
i = 0;
|
i = strlen(lineName);
|
||||||
do {
|
lineName[i] = ',';
|
||||||
if(fwscanf(topList, L"%lc", &names[namesIndex][i]) == 0) goto end;
|
lineName[i + 1] = 0;
|
||||||
}
|
utf8ToWide(lineName, names[namesIndex], 100);
|
||||||
while(names[namesIndex][i++] != L',');
|
|
||||||
names[namesIndex][i] = 0;
|
|
||||||
|
|
||||||
fwscanf(topList, L"%d", &points[namesIndex]);
|
|
||||||
fwscanf(topList, L"\n");
|
|
||||||
if(namesIndex < topListItemsMax - 1) namesIndex++;
|
if(namesIndex < topListItemsMax - 1) namesIndex++;
|
||||||
else sortTopList();
|
else sortTopList();
|
||||||
}
|
}
|
||||||
end:
|
sortTopList();
|
||||||
sortTopList();
|
fclose(topList);
|
||||||
fclose(topList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,9 +159,10 @@ void loadTopList() {
|
||||||
void drawTopList(int deltaTime) {
|
void drawTopList(int deltaTime) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < namesIndex; i++) {
|
for(i = 0; i < namesIndex; i++) {
|
||||||
Uint16 nameWScore[600];
|
char storedName[400], nameWScore[600];
|
||||||
swprintf(nameWScore, L"%ls %d", names[i], points[i]);
|
wideToUtf8(names[i], storedName, sizeof(storedName));
|
||||||
unicodePrintCentered(nameWScore, 50, 20 + ((i == 0) ? 0 : (i + 1)*infoTav), (i == 0) ? large : (i == 1) ? small : tiny);
|
snprintf(nameWScore, sizeof(nameWScore), "%s %d", storedName, points[i]);
|
||||||
|
utf8PrintCentered(nameWScore, 50, 20 + ((i == 0) ? 0 : (i + 1)*infoTav), (i == 0) ? large : (i == 1) ? small : tiny);
|
||||||
}
|
}
|
||||||
|
|
||||||
printBack();
|
printBack();
|
||||||
|
|
@ -175,7 +171,7 @@ void drawTopList(int deltaTime) {
|
||||||
|
|
||||||
///Ha a játékos szüneteltei a játékot(ESC) ezt fogja látni. Elég drága az átlátszó box, szóval csak óvatosan a méretével.
|
///Ha a játékos szüneteltei a játékot(ESC) ezt fogja látni. Elég drága az átlátszó box, szóval csak óvatosan a méretével.
|
||||||
void drawPauseMenu(bool saved) {
|
void drawPauseMenu(bool saved) {
|
||||||
Uint16 pauseOptions[][100] = {
|
wchar_t pauseOptions[][100] = {
|
||||||
L"Játék folytatása",
|
L"Játék folytatása",
|
||||||
L"Pálya elmentése",
|
L"Pálya elmentése",
|
||||||
L"Mentés betöltése",
|
L"Mentés betöltése",
|
||||||
|
|
@ -201,14 +197,14 @@ void drawLoadMenu(int deltaTime) {
|
||||||
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
Uint16 timeStrings[][50] = {
|
const char* timeStrings[] = {
|
||||||
L"másodperccel",
|
"másodperccel",
|
||||||
L"perccel",
|
"perccel",
|
||||||
L"órával",
|
"órával",
|
||||||
L"nappal",
|
"nappal",
|
||||||
L"héttel",
|
"héttel",
|
||||||
L"hónappal",
|
"hónappal",
|
||||||
L"évvel"
|
"évvel"
|
||||||
};
|
};
|
||||||
int timeConversion[] = {
|
int timeConversion[] = {
|
||||||
1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, 60*60*24*365
|
1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, 60*60*24*365
|
||||||
|
|
@ -224,9 +220,9 @@ void drawLoadMenu(int deltaTime) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int elapsedSaveTime = deltaRealTime / timeConversion[timeStringsIndex];
|
int elapsedSaveTime = deltaRealTime / timeConversion[timeStringsIndex];
|
||||||
Uint16 save[200];
|
char save[300];
|
||||||
swprintf(save, L"%d %ls ezelőtti mentés, %d ponttal", elapsedSaveTime, timeStrings[timeStringsIndex], points[i]);
|
snprintf(save, sizeof(save), "%d %s ezelőtti mentés, %d ponttal", elapsedSaveTime, timeStrings[timeStringsIndex], points[i]);
|
||||||
unicodePrintCentered(save, 50, loadStart + k * loadTav, isMouseOverRect(50, loadStart + loadTav*k, 25, 3) ? smallBold : small);
|
utf8PrintCentered(save, 50, loadStart + k * loadTav, isMouseOverRect(50, loadStart + loadTav*k, 25, 3) ? smallBold : small);
|
||||||
unicodePrintCentered(L"Törlés", 50, loadStart + k * loadTav + 5, isMouseOverRect(50, loadStart + loadTav*k + 5, 25, 2) ? smallBold : small);
|
unicodePrintCentered(L"Törlés", 50, loadStart + k * loadTav + 5, isMouseOverRect(50, loadStart + loadTav*k + 5, 25, 2) ? smallBold : small);
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
int currentOptions[] = {2000, 2000, 3, 450, 6000};
|
int currentOptions[] = {2000, 2000, 3, 450, 6000};
|
||||||
int currentSpawnRate, fadeStartTime, elapsedTime = 0, nameIndex = 0, cursorBlinking = 0;
|
int currentSpawnRate, fadeStartTime, elapsedTime = 0, nameIndex = 0, cursorBlinking = 0;
|
||||||
|
|
||||||
bool prematureClick, isDollying, saved = false;
|
bool isDollying, saved = false;
|
||||||
Uint16 name[100] = {0};
|
wchar_t name[100] = {0};
|
||||||
FILE* topList;
|
FILE* topList;
|
||||||
|
|
||||||
states gameState = mainMenu; /**< Kezdőállapot. */
|
states gameState = mainMenu; /**< Kezdőállapot. */
|
||||||
|
|
@ -39,9 +39,6 @@ void handleClicks(bool* prematureClick) {
|
||||||
}
|
}
|
||||||
else if(isMouseOverRect(50, menuStart + menuTav*4, 15, menuTav / 2))
|
else if(isMouseOverRect(50, menuStart + menuTav*4, 15, menuTav / 2))
|
||||||
gameState = infoMenu;
|
gameState = infoMenu;
|
||||||
else if(isMouseOverRect(50, menuStart + menuTav*5, 15, menuTav / 2)) {
|
|
||||||
gameState = quit;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case pauseMenu:
|
case pauseMenu:
|
||||||
if(isMouseOverRect(50, menuStart - 5, 15, menuTav/2)) {
|
if(isMouseOverRect(50, menuStart - 5, 15, menuTav/2)) {
|
||||||
|
|
@ -181,11 +178,10 @@ void doStuff(bool isLMBDown, bool isRMBDown, bool prematureClick) {
|
||||||
boxRGBA(screen, 0, 0, screen -> w, screen -> h, 0, 0, 0, 255);
|
boxRGBA(screen, 0, 0, screen -> w, screen -> h, 0, 0, 0, 255);
|
||||||
cursorBlinking += deltaTime;
|
cursorBlinking += deltaTime;
|
||||||
if(cursorBlinking > 1000) cursorBlinking = 0;
|
if(cursorBlinking > 1000) cursorBlinking = 0;
|
||||||
Uint16 loseText[300];
|
char typedName[400], loseText[600];
|
||||||
swprintf(loseText, L"%ls vesztett, a pontszáma %d.", cursorBlinking > 500 ? L"|" : L"", getPoints());
|
wideToUtf8(name, typedName, sizeof(typedName));
|
||||||
Uint16* endText = concatUnicode(name, loseText);
|
snprintf(loseText, sizeof(loseText), "%s%s vesztett, a pontszáma %d.", typedName, cursorBlinking > 500 ? "|" : "", getPoints());
|
||||||
unicodePrintCentered(endText, 50, 50, small);
|
utf8PrintCentered(loseText, 50, 50, small);
|
||||||
free(endText);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(isAlive()) drawMouse(isInSlowMo);
|
if(isAlive()) drawMouse(isInSlowMo);
|
||||||
|
|
@ -199,7 +195,9 @@ static void escapeFromNameInput() {
|
||||||
createMenuWorld();
|
createMenuWorld();
|
||||||
topList = fopen("rang.lst", "a");
|
topList = fopen("rang.lst", "a");
|
||||||
if(topList != NULL) {
|
if(topList != NULL) {
|
||||||
fwprintf(topList, L"%ls,%d\n", name[0] == 0 ? L"Névtelen" : name, getPoints());
|
char utf8[400];
|
||||||
|
wideToUtf8(name[0] == 0 ? L"Névtelen" : name, utf8, sizeof(utf8));
|
||||||
|
fprintf(topList, "%s,%d\n", utf8, getPoints());
|
||||||
fclose(topList);
|
fclose(topList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -218,9 +216,6 @@ void whatToDoOnEscape() {
|
||||||
saved = false;
|
saved = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case mainMenu:
|
|
||||||
gameState = quit;
|
|
||||||
break;
|
|
||||||
case fading:
|
case fading:
|
||||||
gameState = nameInput;
|
gameState = nameInput;
|
||||||
break;
|
break;
|
||||||
|
|
@ -233,13 +228,27 @@ void whatToDoOnEscape() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///A szöveges bemenetet továbbítja egy Uint16-os stringbe.
|
///A szöveges bemenetet továbbítja egy wchar_t-os stringbe.
|
||||||
void processTyping(SDL_Event event) {
|
void processTyping(SDL_Event event) {
|
||||||
if(gameState == nameInput) {
|
if(gameState == nameInput) {
|
||||||
Uint16 chr = event.key.keysym.unicode;
|
SDL_Keycode key = event.key.keysym.sym;
|
||||||
if(strcmp(SDL_GetKeyName(chr), "backspace") == 0) name[--nameIndex] = 0;
|
if(key == SDLK_BACKSPACE) { if(nameIndex > 0) name[--nameIndex] = 0; }
|
||||||
else if(strcmp(SDL_GetKeyName(chr), "return") == 0) escapeFromNameInput();
|
else if(key == SDLK_RETURN || key == SDLK_KP_ENTER) escapeFromNameInput();
|
||||||
else if(isValidChar(chr)) name[nameIndex++] = chr;
|
name[nameIndex] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///A beírt karaktereket utf-8-ból átalakítva fűzi a névhez.
|
||||||
|
void processTextInput(const char* utf8) {
|
||||||
|
if(gameState == nameInput) {
|
||||||
|
wchar_t typed[16];
|
||||||
|
int count = utf8ToWide(utf8, typed, sizeof(typed) / sizeof(wchar_t));
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < count; i++)
|
||||||
|
if(isValidChar(typed[i]) && nameIndex < (int) (sizeof(name) / sizeof(wchar_t)) - 1)
|
||||||
|
name[nameIndex++] = typed[i];
|
||||||
|
|
||||||
name[nameIndex] = 0;
|
name[nameIndex] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,6 @@
|
||||||
void doStuff(bool isLMBDown, bool isRMBDown, bool prematureClick);
|
void doStuff(bool isLMBDown, bool isRMBDown, bool prematureClick);
|
||||||
void whatToDoOnEscape();
|
void whatToDoOnEscape();
|
||||||
void processTyping(SDL_Event event);
|
void processTyping(SDL_Event event);
|
||||||
|
void processTextInput(const char* utf8);
|
||||||
|
|
||||||
#endif // MENUFSM_H_INCLUDED
|
#endif // MENUFSM_H_INCLUDED
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
typedef struct particle {
|
typedef struct particle {
|
||||||
//y, z
|
//y, z
|
||||||
vector2D position;
|
vector2D position;
|
||||||
//mert kockák
|
//mert kockák
|
||||||
float size;
|
float size;
|
||||||
float velocity;
|
float velocity;
|
||||||
} particle;
|
} particle;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ vector2D playerVelocity; /**< A játékos sebesség [m/ms], a delta time
|
||||||
int directionOfMovement = 0; /**< A mozgás iránya, lehet -1, 0, +1. */
|
int directionOfMovement = 0; /**< A mozgás iránya, lehet -1, 0, +1. */
|
||||||
bool isJumping = false, isFalling = true;
|
bool isJumping = false, isFalling = true;
|
||||||
bool isDead = false;
|
bool isDead = false;
|
||||||
int points; /**< Mennyi pontot gyűjtött eddig a játékos. Ez nőhet és gyökkenhet is, de mindig >= 0. */
|
static int points; /**< Mennyi pontot gyűjtött eddig a játékos. Ez nőhet és gyökkenhet is, de mindig >= 0. */
|
||||||
|
|
||||||
|
|
||||||
void setDie(bool newValue) {
|
void setDie(bool newValue) {
|
||||||
|
|
@ -29,6 +29,7 @@ void updateText(int newPoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawPointsText() {
|
void drawPointsText() {
|
||||||
|
if(!isRenderingEnabled()) return;
|
||||||
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){50, 30, 0, 0});
|
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){50, 30, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,9 +57,9 @@ int getPoints() {
|
||||||
void movePlayer(unsigned char* keys, int deltaTime) {
|
void movePlayer(unsigned char* keys, int deltaTime) {
|
||||||
|
|
||||||
//nem a legszebb, de a rövidségtől szép lesz.
|
//nem a legszebb, de a rövidségtől szép lesz.
|
||||||
directionOfMovement = (keys[SDLK_d] || keys[SDLK_RIGHT]) - (keys[SDLK_a] || keys[SDLK_LEFT]);
|
directionOfMovement = (keys[SDL_SCANCODE_D] || keys[SDL_SCANCODE_RIGHT]) - (keys[SDL_SCANCODE_A] || keys[SDL_SCANCODE_LEFT]);
|
||||||
|
|
||||||
isJumping = keys[SDLK_w] || keys[SDLK_UP] || keys[SDLK_SPACE];
|
isJumping = keys[SDL_SCANCODE_W] || keys[SDL_SCANCODE_UP] || keys[SDL_SCANCODE_SPACE];
|
||||||
//<\input feldolgozása>
|
//<\input feldolgozása>
|
||||||
//<sebesség kiszámítása>
|
//<sebesség kiszámítása>
|
||||||
if(directionOfMovement != 0) {
|
if(directionOfMovement != 0) {
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,15 @@ void getExistingSaveFiles(time_t ages[], int points[]) {
|
||||||
char save[50];
|
char save[50];
|
||||||
FILE* saveFile;
|
FILE* saveFile;
|
||||||
while(saveID < maxNOSaves) {
|
while(saveID < maxNOSaves) {
|
||||||
sprintf(save, "saves\\game%d.save", saveID);
|
sprintf(save, "saves/game%d.save", saveID);
|
||||||
saveFile = fopen(save, "r");
|
saveFile = fopen(save, "r");
|
||||||
if(saveFile != NULL) {
|
if(saveFile != NULL) {
|
||||||
existingSaves[saveID] = true;
|
existingSaves[saveID] = true;
|
||||||
if(saveFile != NULL) {
|
if(saveFile != NULL) {
|
||||||
if(ages != NULL) {
|
if(ages != NULL) {
|
||||||
fscanf(saveFile, "%ld,", &(ages[saveID]));
|
long long savedTime = 0;
|
||||||
|
fscanf(saveFile, "%lld,", &savedTime);
|
||||||
|
ages[saveID] = (time_t) savedTime;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 8; i++)
|
for(i = 0; i < 8; i++)
|
||||||
fscanf(saveFile, "%d,", &(points[saveID]));
|
fscanf(saveFile, "%d,", &(points[saveID]));
|
||||||
|
|
@ -29,7 +31,7 @@ void getExistingSaveFiles(time_t ages[], int points[]) {
|
||||||
///Mentés törlése (fizikálisan).
|
///Mentés törlése (fizikálisan).
|
||||||
void deleteSave(int i) {
|
void deleteSave(int i) {
|
||||||
char save[50];
|
char save[50];
|
||||||
sprintf(save, "saves\\game%d.save", i);
|
sprintf(save, "saves/game%d.save", i);
|
||||||
remove(save);
|
remove(save);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,12 +50,12 @@ void saveGame(int currentOptions[]) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < maxNOSaves - 1 && existingSaves[i]; i++)
|
for(i = 0; i < maxNOSaves - 1 && existingSaves[i]; i++)
|
||||||
;
|
;
|
||||||
sprintf(saveName, "saves\\game%d.save", i);
|
sprintf(saveName, "saves/game%d.save", i);
|
||||||
FILE* save = fopen(saveName, "w");
|
FILE* save = fopen(saveName, "w");
|
||||||
|
|
||||||
block** map = getMap();
|
block** map = getMap();
|
||||||
|
|
||||||
fprintf(save, "%ld,", time(NULL));
|
fprintf(save, "%lld,", (long long) time(NULL));
|
||||||
for(i = 0; i < 5; i++)
|
for(i = 0; i < 5; i++)
|
||||||
fprintf(save, "%d,", currentOptions[i]);
|
fprintf(save, "%d,", currentOptions[i]);
|
||||||
|
|
||||||
|
|
@ -82,13 +84,13 @@ void saveGame(int currentOptions[]) {
|
||||||
bufferIndex += strlen(temp);
|
bufferIndex += strlen(temp);
|
||||||
}
|
}
|
||||||
if(bufferIndex > bufferSize - 20) {
|
if(bufferIndex > bufferSize - 20) {
|
||||||
fprintf(save, buffer);
|
fprintf(save, "%s", buffer);
|
||||||
bufferIndex = 0;
|
bufferIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(bufferIndex != 0)
|
if(bufferIndex != 0)
|
||||||
fprintf(save, buffer);
|
fprintf(save, "%s", buffer);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
fclose(save);
|
fclose(save);
|
||||||
|
|
@ -97,12 +99,12 @@ void saveGame(int currentOptions[]) {
|
||||||
///Fájlból betölti a játékot, a világot is előkészíti. A mentésnél használt tömörítést dekódolja. A betöltött játék beállítások felülírják az eddigieket.
|
///Fájlból betölti a játékot, a világot is előkészíti. A mentésnél használt tömörítést dekódolja. A betöltött játék beállítások felülírják az eddigieket.
|
||||||
void loadGame(int currentOptions[], int saveID) {
|
void loadGame(int currentOptions[], int saveID) {
|
||||||
char saveName[50];
|
char saveName[50];
|
||||||
sprintf(saveName, "saves\\game%d.save", saveID);
|
sprintf(saveName, "saves/game%d.save", saveID);
|
||||||
|
|
||||||
FILE* save = fopen(saveName, "r");
|
FILE* save = fopen(saveName, "r");
|
||||||
|
|
||||||
time_t tmpT;
|
long long tmpT;
|
||||||
fscanf(save, "%ld,", &tmpT);
|
fscanf(save, "%lld,", &tmpT);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 5; i++)
|
for(i = 0; i < 5; i++)
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue