Imrpove frontends

This commit is contained in:
Miloslav Číž 2020-10-28 16:41:23 +01:00
parent fa7d8d7bd9
commit 42035de744
6 changed files with 132 additions and 71 deletions

View File

@ -152,6 +152,11 @@ Why go back to the 90s and not further? Early 90s is roughly right before PCs an
What we perceive as good graphics is heavily dependant on what we've learned to perceive as good graphics, and it's more about aesthetics than things like resolution or polygon count. Doom looked amazing when it came out and it still does today to people who didn't let the industry teach them that good graphics equals super HD with realistic shaders requiring the latest and most expensive GPU.
### Why doesn't this have feature X? Even Doom had it.
Though inspired by Doom, this is **NOT** Doom. Keep in mind that this isn't primarily a PC game, this is a small platform independent game that happens to also natively run on PC. Also this game's goals are different than those of commercial games, it is still to a big degree just an experimental game. It has been written by a single person who had to do the design, engine programming, game programming, tool programming, graphics, sound recording, media creation, all in spare time.
Please don't hate me.
### Shouldn't games simply be fun? You're complicating everything with ideological bullshit when it's really just about entertainment.
Games should definitely be fun to play, but they are still technology and engineering art. We have more than enough games that are trying to be just fun before everything else, but practically none putting a little more emphasis also on other aspects -- projects that don't spend all the effort on the shallow shell, but care equally about the insides and the wider context of the world they exist in. I think we need many more games like this one.
@ -178,7 +183,7 @@ Python scripts are only simple helpers for converting resources, which aren't re
### Why aren't you writing in assembly then?
Because assembly isn't portable and even a "portable assembly" (bytecode) would make it too difficult to write a game of this complexity. C is about the minimum required abstraction.
Because assembly isn't portable and even a "portable assembly" (bytecode) would make it too difficult to write a game of this complexity, and still probably wouldn't be as portable as C. C is about the minimum required abstraction.
### So I can do anything with this for free? Even like sell it and stuff?

10
game.h
View File

@ -1,8 +1,8 @@
/**
@file game.h
Main source file of the game that puts together all the pieces. main game
logic is implemented here.
Main source file of Anarch the game that puts together all the pieces. main
game logic is implemented here.
Physics notes (you can break this when messing with constants):
@ -23,13 +23,11 @@
#ifndef _SFG_GAME_H
#define _SFG_GAME_H
#include <stdint.h>
#include <stdint.h> // Needed for fixed width types, can easily be replaced.
/*
The following keys are mandatory to be implemented on any platform in order
for the game to be playable.
Enums are bloat :)
for the game to be playable. Enums are bloat.
*/
#define SFG_KEY_UP 0
#define SFG_KEY_RIGHT 1

View File

@ -2,8 +2,8 @@
@file main_csfml.c
This is a csfml (C binding for SFML) implementation of the game front end.
This is another alternative to the SDL for the PC. This front end is more
minimal and simple than the SDL, so it's better as a learning resource.
This is another alternative to the SDL for the PC. This front end is maybe a
little simpler than the SDL, so it's better as a learning resource.
by Miloslav Ciz (drummyfish), 2020
@ -27,6 +27,9 @@
#define SFG_DITHERED_SHADOW 1
#define SFG_DIMINISH_SPRITES 1
#define SFG_RESOLUTION_SCALEDOWN 1
#define SFG_BACKGROUND_BLUR 1
#define SFG_LOG(s) printf("game: %s\n",s);
#define MUSIC_VOLUME 16
@ -58,9 +61,9 @@ int8_t SFG_keyPressed(uint8_t key)
return k(S) || k(Down) || k(Num5) || k (Num2); break;
case SFG_KEY_LEFT: return k(Q) || k(Left) || k(Num4); break;
case SFG_KEY_A:
return k(J) || k(Return) || k(LShift) ||
return k(J) || k(Return) || k(LControl) || k(RControl) ||
sfMouse_isButtonPressed(sfMouseLeft); break;
case SFG_KEY_B: return k(K) || k(LControl) || k(RControl); break;
case SFG_KEY_B: return k(K) || k(LShift); break;
case SFG_KEY_C: return k(L); break;
case SFG_KEY_JUMP: return k(Space); break;
case SFG_KEY_STRAFE_LEFT: return k(A) || k(Num7); break;
@ -75,11 +78,10 @@ int8_t SFG_keyPressed(uint8_t key)
if (k(P) || k(X))
return 1;
if (mouseWheelState > 0)
{
mouseWheelState--;
return 1;
}
#define checkMouse(cmp)\
if (mouseWheelState cmp 0) { mouseWheelState = 0; return 1; }
checkMouse(>)
return 0;
break;
@ -88,11 +90,9 @@ int8_t SFG_keyPressed(uint8_t key)
if (k(O) || k(Y) || k(Z))
return 1;
if (mouseWheelState < 0)
{
mouseWheelState++;
return 1;
}
checkMouse(<)
#undef checkMouse
return 0;
break;
@ -251,14 +251,70 @@ void soundSeek(sfTime t, void *userData)
{
}
int main()
uint32_t screenshotNumber = 0;
/**
Saves a screenshot using the simple uncompressed PPM file format.
*/
void screenshot()
{
char fileName[64];
sprintf(fileName,"screenshot_%05d.ppm",screenshotNumber);
FILE *f = fopen(fileName,"w");
if (!f)
{
puts("error: could not take screenshot");
return;
}
fprintf(f,"P6 %d %d 255\n",SFG_SCREEN_RESOLUTION_X,SFG_SCREEN_RESOLUTION_Y);
for (uint32_t i = 0; i < WINDOW_SIZE; ++i)
fwrite(&windowPixels[i],1,3,f);
puts("screenshot taken");
screenshotNumber++;
fclose(f);
}
int main(int argc, char *argv[])
{
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h' && argv[1][2] == 0)
{
puts("Anarch (CSFML), version " SFG_VERSION_STRING "\n");
puts("Anarch is a unique suckless FPS game. Collect weapons and items and destroy");
puts("robot enemies in your way in order to get to the level finish. Some door are");
puts("locked and require access cards. Good luck!\n");
puts("created by Miloslav \"drummyfish\" Ciz, 2020, released under CC0 1.0 (public domain)\n");
puts("controls:\n");
puts("- arrows, numpad, [W] [S] [A] [D] [Q] [R]: movement");
puts("- mouse: rotation, [LMB] shoot, [RMB] toggle free look");
puts("- [SPACE]: jump");
puts("- [J] [RETURN] [CTRL] [LMB]: game A button (shoot, confirm)");
puts("- [K] [SHIFT]: game B button (cancel, strafe)");
puts("- [L]: game C button (+ down = menu, + up = jump, ...)");
puts("- [F]: cycle next/previous weapon");
puts("- [O] [P] [X] [Y] [Z] [mouse wheel]: change weapons");
puts("- [TAB]: map");
puts("- [F12]: screenshot");
puts("- [ESCAPE]: menu");
return 0;
}
SFG_init();
sfVideoMode mode = {SFG_SCREEN_RESOLUTION_X, SFG_SCREEN_RESOLUTION_Y, 32};
sfEvent event;
clock = sfClock_create();
sfClock_restart(clock);
SFG_init();
puts("initializing");
for (int i = 0; i < AUDIO_BUFFER_SIZE; ++i)
audioBuffer[i] = 0;
@ -288,6 +344,8 @@ int main()
sfSoundStream_play(sound);
puts("starting");
while (sfRenderWindow_isOpen(window))
{
while (sfRenderWindow_pollEvent(window,&event))
@ -295,6 +353,8 @@ int main()
sfRenderWindow_close(window);
else if (event.type == sfEvtMouseWheelMoved)
mouseWheelState = event.mouseWheel.delta;
else if (event.type == sfEvtKeyPressed && event.key.code == sfKeyF12)
screenshot();
if (!SFG_mainLoopBody())
break;
@ -306,6 +366,8 @@ int main()
sfRenderWindow_display(window);
}
puts("ending");
sfSoundStream_stop(sound);
sfSoundStream_destroy(sound);
sfSprite_destroy(windowSprite);

View File

@ -30,10 +30,7 @@
#define SFG_UNLOCK_DOOR 1
// #define SFG_REVEAL_MAP 1
#define SFG_INFINITE_AMMO 1
// #define SFG_TIME_MULTIPLIER 512
// uncomment for perfomance debug
// #define SFG_CPU_LOAD(percent) printf("CPU load: %d%\n",percent);
#ifndef __EMSCRIPTEN__
@ -70,20 +67,13 @@
#include <emscripten.h>
#endif
// #define SFG_SCREEN_RESOLUTION_X 88
// #define SFG_SCREEN_RESOLUTION_Y 110
// #define SFG_SCREEN_RESOLUTION_X 80
// #define SFG_SCREEN_RESOLUTION_Y 64
/*
SDL is easier to play thanks to nice controls, so make the player take full
SDL is easier to play thanks to nice controls so make the player take full
damage to make it a bit harder.
*/
#define SFG_PLAYER_DAMAGE_MULTIPLIER 1024
#define MUSIC_VOLUME 16
#define SDL_MUSIC_VOLUME 16
#if !SFG_OS_IS_MALWARE
#include <signal.h>
@ -101,16 +91,18 @@ uint8_t webKeyboardState[SFG_KEY_COUNT];
uint8_t sdlMouseButtonState = 0;
int8_t sdlMouseWheelState = 0;
uint16_t screen[SFG_SCREEN_RESOLUTION_X * SFG_SCREEN_RESOLUTION_Y]; // RGB565 format
uint16_t sdlScreen[SFG_SCREEN_RESOLUTION_X * SFG_SCREEN_RESOLUTION_Y]; // RGB565
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
SDL_Surface *screenSurface;
// now implement the Anarch API functions (SFG_*)
void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex)
{
screen[y * SFG_SCREEN_RESOLUTION_X + x] = paletteRGB565[colorIndex];
sdlScreen[y * SFG_SCREEN_RESOLUTION_X + x] = paletteRGB565[colorIndex];
}
uint32_t SFG_getTimeMs()
@ -154,6 +146,7 @@ uint8_t SFG_load(uint8_t data[SFG_SAVE_SIZE])
return 1;
#else
// no saving for web version
return 0;
#endif
}
@ -166,7 +159,7 @@ void SFG_sleepMs(uint16_t timeMs)
}
#ifdef __EMSCRIPTEN__
void webButton(uint8_t key, uint8_t down)
void webButton(uint8_t key, uint8_t down) // HTML button pressed
{
webKeyboardState[key] = down;
}
@ -200,7 +193,7 @@ void SFG_processEvent(uint8_t event, uint8_t data)
int8_t SFG_keyPressed(uint8_t key)
{
if (webKeyboardState[key])
if (webKeyboardState[key]) // this only takes effect in the web version
return 1;
#define k(x) sdlKeyboardState[SDL_SCANCODE_ ## x]
@ -211,9 +204,9 @@ int8_t SFG_keyPressed(uint8_t key)
case SFG_KEY_RIGHT: return k(RIGHT) || k(E) || k(KP_6); break;
case SFG_KEY_DOWN: return k(DOWN) || k(S) || k(KP_5) || k(KP_2); break;
case SFG_KEY_LEFT: return k(LEFT) || k(Q) || k(KP_4); break;
case SFG_KEY_A: return k(J) || k(RETURN) || k(LSHIFT) ||
case SFG_KEY_A: return k(J) || k(RETURN) || k(LCTRL) || k(RCTRL) ||
(sdlMouseButtonState & SDL_BUTTON_LMASK); break;
case SFG_KEY_B: return k(K) || k(LCTRL) || k(RCTRL); break;
case SFG_KEY_B: return k(K) || k(LSHIFT); break;
case SFG_KEY_C: return k(L); break;
case SFG_KEY_JUMP: return k(SPACE); break;
case SFG_KEY_STRAFE_LEFT: return k(A) || k(KP_7); break;
@ -227,11 +220,10 @@ int8_t SFG_keyPressed(uint8_t key)
if (k(P) || k(X))
return 1;
if (sdlMouseWheelState > 0)
{
sdlMouseWheelState = 0;
return 1;
}
#define checkMouse(cmp)\
if (sdlMouseWheelState cmp 0) { sdlMouseWheelState = 0; return 1; }
checkMouse(>)
return 0;
break;
@ -240,11 +232,9 @@ int8_t SFG_keyPressed(uint8_t key)
if (k(O) || k(Y) || k(Z))
return 1;
if (sdlMouseWheelState < 0)
{
sdlMouseWheelState = 0;
return 1;
}
checkMouse(<)
#undef checkMouse
return 0;
break;
@ -262,7 +252,7 @@ void mainLoopIteration()
SDL_Event event;
#ifdef __EMSCRIPTEN__
// Hack, without it sound won't work because of shitty browser audio policies.
// hack, without it sound won't work because of shitty browser audio policies
if (SFG_game.frame % 512 == 0)
SDL_PauseAudio(0);
@ -272,7 +262,7 @@ void mainLoopIteration()
{
if (event.type == SDL_MOUSEWHEEL)
{
if (event.wheel.y > 0) // scroll up
if (event.wheel.y > 0) // scroll up
sdlMouseWheelState = 1;
else if (event.wheel.y < 0) // scroll down
sdlMouseWheelState = -1;
@ -288,7 +278,8 @@ void mainLoopIteration()
if (!SFG_mainLoopBody())
running = 0;
SDL_UpdateTexture(texture,NULL,screen,SFG_SCREEN_RESOLUTION_X * sizeof(uint16_t));
SDL_UpdateTexture(texture,NULL,sdlScreen,
SFG_SCREEN_RESOLUTION_X * sizeof(uint16_t));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer,texture,NULL,NULL);
@ -297,7 +288,8 @@ void mainLoopIteration()
#ifdef __EMSCRIPTEN__
typedef void (*em_callback_func)(void);
void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop);
void emscripten_set_main_loop(
em_callback_func func, int fps, int simulate_infinite_loop);
#endif
uint16_t audioBuff[SFG_SFX_SAMPLE_COUNT];
@ -319,7 +311,7 @@ void audioFillCallback(void *userdata, uint8_t *s, int l)
for (int i = 0; i < l / 2; ++i)
{
s16[i] = musicOn ?
mixSamples(audioBuff[audioPos], MUSIC_VOLUME *
mixSamples(audioBuff[audioPos], SDL_MUSIC_VOLUME *
(SFG_getNextMusicSample() - SFG_musicTrackAverages[SFG_MusicState.track]))
: audioBuff[audioPos];
@ -386,22 +378,24 @@ int main(int argc, char *argv[])
if (argHelp)
{
puts("Anarch, version " SFG_VERSION_STRING "\n");
puts("Anarch (SDL), version " SFG_VERSION_STRING "\n");
puts("Anarch is a unique suckless FPS game. Collect weapons and items and destroy");
puts("robot enemies in your way in order to get to the level finish. Some door are");
puts("locked and require access cards. Good luck!\n");
puts("created by Miloslav \"drummyfish\" Ciz, released under CC0 1.0 (public domain)\n");
puts("created by Miloslav \"drummyfish\" Ciz, 2020, released under CC0 1.0 (public domain)\n");
puts("CLI flags:\n");
puts("-h print this help and exit");
puts("-w force window");
puts("-f force fullscreen\n");
puts("controls:\n");
puts("- arrows, numpad, [W] [S] [A] [D] [Q] [R]: movement");
puts("- mouse: rotation, [LMB] shoot, [RMB] toggle free look, wheel weapon change");
puts("- mouse: rotation, [LMB] shoot, [RMB] toggle free look");
puts("- [SPACE]: jump");
puts("- [G] [RETURN] [SHIFT]: game A button (confirm, strafe)");
puts("- [H] [CTRL]: game B button (cancel, shoot)");
puts("- [O] [P] [X] [Y] [Z]: change weapons");
puts("- [J] [RETURN] [CTRL] [LMB]: game A button (shoot, confirm)");
puts("- [K] [SHIFT]: game B button (cancel, strafe)");
puts("- [L]: game C button (+ down = menu, + up = jump, ...)");
puts("- [F]: cycle next/previous weapon");
puts("- [O] [P] [X] [Y] [Z] [mouse wheel]: change weapons");
puts("- [TAB]: map");
puts("- [ESCAPE]: menu");
@ -485,10 +479,10 @@ int main(int argc, char *argv[])
puts("SDL: freeing SDL");
SDL_PauseAudio(1);
SDL_CloseAudio();
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_CloseAudio();
puts("SDL: ending");

View File

@ -1,11 +1,11 @@
/**
@file main_pokitto.cpp
This is Linux terminal implementation of the game front end. This needs root
priviledges (sudo) to work! This frontend is more of an experiment, don't
expect it to work perfectly and everywhere.
Needs to be run with sudo.
This is Linux terminal implementation of the game front end. If you replace
the input methods, it will most likely run in other terminals as well. This
needs root priviledges (sudo) to work (because we need to read keyboard and
mouse inputs)! This frontend is more of an experiment, don't expect it to work
perfectly and everywhere.
by Miloslav Ciz (drummyfish), 2019
@ -99,14 +99,15 @@ int8_t SFG_keyPressed(uint8_t key)
case SFG_KEY_RIGHT: return input_getKey('d') || input_getKey(SMALLINPUT_ARROW_RIGHT); break;
case SFG_KEY_DOWN: return input_getKey('s') || input_getKey(SMALLINPUT_ARROW_DOWN); break;
case SFG_KEY_LEFT: return input_getKey('a') || input_getKey(SMALLINPUT_ARROW_LEFT); break;
case SFG_KEY_A: return input_getKey('g') || input_getKey(SMALLINPUT_RETURN); break;
case SFG_KEY_B: return input_getKey('h') || input_getKey(SMALLINPUT_MOUSE_L) || input_getKey(SMALLINPUT_CTRL); break;
case SFG_KEY_C: return input_getKey('j'); break;
case SFG_KEY_A: return input_getKey('i') || input_getKey(SMALLINPUT_RETURN) || input_getKey(SMALLINPUT_MOUSE_L); break;
case SFG_KEY_B: return input_getKey('j') || input_getKey(SMALLINPUT_CTRL); break;
case SFG_KEY_C: return input_getKey('k'); break;
case SFG_KEY_MAP: return input_getKey(SMALLINPUT_TAB); break;
case SFG_KEY_JUMP: return input_getKey(' '); break;
case SFG_KEY_MENU: return input_getKey(SMALLINPUT_ESCAPE); break;
case SFG_KEY_NEXT_WEAPON: return input_getKey('2'); break;
case SFG_KEY_PREVIOUS_WEAPON: return input_getKey('1'); break;
case SFG_KEY_CYCLE_WEAPON: return input_getKey('f'); break;
case SFG_KEY_TOGGLE_FREELOOK: return input_getKey(SMALLINPUT_MOUSE_R); break;
default: return 0; break;
}

View File

@ -18,6 +18,7 @@ everything else in this repository.
\ /
'-.__ __.-'
'''''
share on:
- own website
- itch.io