mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add aquatinspitz(1).
This commit is contained in:
parent
559857b97e
commit
8e86952abf
3 changed files with 394 additions and 0 deletions
1
games/.gitignore
vendored
1
games/.gitignore
vendored
|
@ -5,3 +5,4 @@
|
||||||
*.so
|
*.so
|
||||||
*.a
|
*.a
|
||||||
asteroids
|
asteroids
|
||||||
|
aquatinspitz
|
||||||
|
|
|
@ -11,6 +11,7 @@ CXXFLAGS:=$(CXXFLAGS) -Wall -Wextra -fno-exceptions -fno-rtti
|
||||||
|
|
||||||
BINARIES:=\
|
BINARIES:=\
|
||||||
asteroids \
|
asteroids \
|
||||||
|
aquatinspitz \
|
||||||
|
|
||||||
LIBS:=-ldispd
|
LIBS:=-ldispd
|
||||||
|
|
||||||
|
|
392
games/aquatinspitz.cpp
Normal file
392
games/aquatinspitz.cpp
Normal file
|
@ -0,0 +1,392 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
aquatinspitz.cpp
|
||||||
|
Aqua tin spitz!
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/keycodes.h>
|
||||||
|
#include <sys/termmode.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <error.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <timespec.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <dispd.h>
|
||||||
|
|
||||||
|
// Utility global variables every game will need.
|
||||||
|
bool game_running = true;
|
||||||
|
size_t game_width = 1280;
|
||||||
|
size_t game_height = 720;
|
||||||
|
const size_t MAX_KEY_NUMBER = 512UL;
|
||||||
|
bool keys_down[MAX_KEY_NUMBER] = { false };
|
||||||
|
bool keys_pending[MAX_KEY_NUMBER] = { false };
|
||||||
|
struct timespec key_handled_last[MAX_KEY_NUMBER];
|
||||||
|
|
||||||
|
// Utility functions every game will need.
|
||||||
|
bool pop_is_key_just_down(int abskbkey);
|
||||||
|
static inline uint32_t make_color(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
|
||||||
|
// Your game is customized from here ...
|
||||||
|
|
||||||
|
struct player
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct player player;
|
||||||
|
|
||||||
|
struct enemy
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float vx;
|
||||||
|
float vy;
|
||||||
|
int size;
|
||||||
|
int shift;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUM_ENEMIES 256
|
||||||
|
struct enemy enemies[NUM_ENEMIES];
|
||||||
|
|
||||||
|
// Prepare the game state for the first round.
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
player.x = game_width / 2;
|
||||||
|
player.y = game_height / 2;
|
||||||
|
player.size = 24.0;
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < NUM_ENEMIES; i++ )
|
||||||
|
{
|
||||||
|
enemies[i].x = (float) arc4random_uniform(game_width);
|
||||||
|
enemies[i].y = (float) arc4random_uniform(game_height);
|
||||||
|
enemies[i].vx = (float) ((int) arc4random_uniform(96) - 48);
|
||||||
|
enemies[i].vy = (float) ((int) arc4random_uniform(96) - 48);
|
||||||
|
enemies[i].size = arc4random_uniform(8) + 8;
|
||||||
|
enemies[i].shift = (int) arc4random_uniform(6) - 3;
|
||||||
|
if ( enemies[i].shift <= 0 )
|
||||||
|
enemies[i].shift -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the game state of the next round.
|
||||||
|
void update(float deltatime)
|
||||||
|
{
|
||||||
|
float player_speed = 64.0f;
|
||||||
|
float player_velocity_x = 0.0f;
|
||||||
|
float player_velocity_y = 0.0f;
|
||||||
|
if ( keys_down[KBKEY_UP] )
|
||||||
|
player_velocity_y -= player_speed;
|
||||||
|
if ( keys_down[KBKEY_DOWN] )
|
||||||
|
player_velocity_y += player_speed;
|
||||||
|
if ( keys_down[KBKEY_LEFT] )
|
||||||
|
player_velocity_x -= player_speed;
|
||||||
|
if ( keys_down[KBKEY_RIGHT] )
|
||||||
|
player_velocity_x += player_speed;
|
||||||
|
player.x += deltatime * player_velocity_x;
|
||||||
|
player.y += deltatime * player_velocity_y;
|
||||||
|
|
||||||
|
if ( pop_is_key_just_down(KBKEY_SPACE) )
|
||||||
|
player.size = 192 - player.size;
|
||||||
|
|
||||||
|
float total_speed = 0.0;
|
||||||
|
for ( size_t i = 0; i < NUM_ENEMIES; i++ )
|
||||||
|
{
|
||||||
|
struct enemy* enemy = &enemies[i];
|
||||||
|
float g = 10000.0;
|
||||||
|
float dist_sq = (player.x - enemy->x) * (player.x - enemy->x) +
|
||||||
|
(player.y - enemy->y) * (player.y - enemy->y);
|
||||||
|
if ( dist_sq < 0.1 )
|
||||||
|
dist_sq = 0.1;
|
||||||
|
float dist = sqrtf(dist_sq);
|
||||||
|
float f = g * enemy->size * player.size / dist_sq;
|
||||||
|
float f_x = (player.x - enemy->x) / dist * f;
|
||||||
|
float f_y = (player.y - enemy->y) / dist * f;
|
||||||
|
float a_x = f_x / enemy->size;
|
||||||
|
float a_y = f_y / enemy->size;
|
||||||
|
enemy->vx += deltatime * a_x;
|
||||||
|
enemy->vy += deltatime * a_y;
|
||||||
|
float speed = sqrtf(enemy->vx * enemy->vx + enemy->vy * enemy->vy);
|
||||||
|
total_speed += speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float average_speed = total_speed / NUM_ENEMIES;
|
||||||
|
float mid_game = game_width / 2.0;
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < NUM_ENEMIES; i++ )
|
||||||
|
{
|
||||||
|
struct enemy* enemy = &enemies[i];
|
||||||
|
float speed = sqrtf(enemy->vx * enemy->vx + enemy->vy * enemy->vy);
|
||||||
|
float ox = enemy->x;
|
||||||
|
float oy = enemy->y;
|
||||||
|
float nx = ox + deltatime * enemy->vx;
|
||||||
|
float ny = oy + deltatime * enemy->vy;
|
||||||
|
if ( mid_game + enemy->size / 2 < ox &&
|
||||||
|
nx <= mid_game + enemy->size / 2 )
|
||||||
|
{
|
||||||
|
if ( speed < average_speed )
|
||||||
|
{
|
||||||
|
if ( enemy->vx < 0.0 )
|
||||||
|
enemy->vx = -enemy->vx;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( ox <= mid_game - enemy->size / 2 &&
|
||||||
|
mid_game - enemy->size / 2 < nx )
|
||||||
|
{
|
||||||
|
if ( speed >= average_speed )
|
||||||
|
{
|
||||||
|
if ( enemy->vx > 0.0 )
|
||||||
|
enemy->vx = -enemy->vx;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enemy->x = nx;
|
||||||
|
enemy->y = ny;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < NUM_ENEMIES; i++ )
|
||||||
|
{
|
||||||
|
struct enemy* enemy = &enemies[i];
|
||||||
|
if ( enemy->x - enemy->size / 2 < 0 )
|
||||||
|
{
|
||||||
|
enemy->x = 0.0f + enemy->size / 2;
|
||||||
|
if ( enemy->vx < 0.0 )
|
||||||
|
enemy->vx = -0.9 * enemy->vx;
|
||||||
|
}
|
||||||
|
else if ( game_width < (size_t) (enemy->x + enemy->size / 2) )
|
||||||
|
{
|
||||||
|
enemy->x = (float) game_width - enemy->size / 2;
|
||||||
|
if ( 0.0 < enemy->vx )
|
||||||
|
enemy->vx = -0.9 * enemy->vx;
|
||||||
|
}
|
||||||
|
if ( enemy->y - enemy->size / 2 < 0 )
|
||||||
|
{
|
||||||
|
enemy->y = 0.0f + enemy->size / 2;
|
||||||
|
if ( enemy->vy < 0.0 )
|
||||||
|
enemy->vy = -0.9 * enemy->vy;
|
||||||
|
}
|
||||||
|
else if ( game_height < (size_t) (enemy->y + enemy->size / 2) )
|
||||||
|
{
|
||||||
|
enemy->y = (float) game_height - enemy->size / 2;
|
||||||
|
if ( 0.0 < enemy->vy )
|
||||||
|
enemy->vy = -0.9 * enemy->vy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the game into the framebuffer.
|
||||||
|
void render(struct dispd_window* window)
|
||||||
|
{
|
||||||
|
struct dispd_framebuffer* window_fb = dispd_begin_render(window);
|
||||||
|
if ( !window_fb )
|
||||||
|
{
|
||||||
|
error(0, 0, "unable to begin rendering dispd window");
|
||||||
|
game_running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* fb = (uint32_t*) dispd_get_framebuffer_data(window_fb);
|
||||||
|
size_t xres = dispd_get_framebuffer_width(window_fb);
|
||||||
|
size_t yres = dispd_get_framebuffer_height(window_fb);
|
||||||
|
size_t pitch = dispd_get_framebuffer_pitch(window_fb) / sizeof(uint32_t);
|
||||||
|
|
||||||
|
// Render a colorful background.
|
||||||
|
for ( size_t y = 0; y < yres; y++ )
|
||||||
|
{
|
||||||
|
for ( size_t x = 0; x < xres; x++ )
|
||||||
|
{
|
||||||
|
uint32_t color = make_color(x * y, y ? x / y : 255, x ^ y);
|
||||||
|
fb[y * pitch + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the player.
|
||||||
|
for ( int t = -player.size / 2; t < player.size / 2; t++ )
|
||||||
|
{
|
||||||
|
if ( player.y + t < 0 )
|
||||||
|
continue;
|
||||||
|
size_t y = (size_t) (player.y + t);
|
||||||
|
if ( yres <= y )
|
||||||
|
continue;
|
||||||
|
for ( int l = -player.size / 2; l < player.size / 2; l++ )
|
||||||
|
{
|
||||||
|
if ( player.x + l < 0 )
|
||||||
|
continue;
|
||||||
|
size_t x = (size_t) (player.x + l);
|
||||||
|
if ( xres <= x )
|
||||||
|
continue;
|
||||||
|
uint32_t background = fb[y * pitch + x];
|
||||||
|
uint32_t color = ~background;
|
||||||
|
fb[y * pitch + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the enemies.
|
||||||
|
for ( size_t i = 0; i < NUM_ENEMIES; i++ )
|
||||||
|
{
|
||||||
|
struct enemy* enemy = &enemies[i];
|
||||||
|
for ( int t = -enemy->size / 2; t < enemy->size / 2; t++ )
|
||||||
|
{
|
||||||
|
if ( enemy->y + t < 0 )
|
||||||
|
continue;
|
||||||
|
size_t y = (size_t) (enemy->y + t);
|
||||||
|
if ( yres <= y )
|
||||||
|
continue;
|
||||||
|
for ( int l = -enemy->size / 2; l < enemy->size / 2; l++ )
|
||||||
|
{
|
||||||
|
if ( enemy->x + l < 0 )
|
||||||
|
continue;
|
||||||
|
size_t x = (size_t) (enemy->x + l);
|
||||||
|
if ( xres <= x )
|
||||||
|
continue;
|
||||||
|
uint32_t background = fb[y * pitch + x];
|
||||||
|
uint32_t color = enemy->shift < 0 ? background >> -enemy->shift
|
||||||
|
: background << enemy->shift;
|
||||||
|
color = ~color;
|
||||||
|
fb[y * pitch + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispd_finish_render(window_fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... to here. No need to edit stuff below.
|
||||||
|
|
||||||
|
// Create a color from rgb values.
|
||||||
|
static inline uint32_t make_color(uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
|
return b << 0UL | g << 8UL | r << 16UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if a keystroke is pending. For instance, if you press A on your
|
||||||
|
// keyboard and keep pressing it, a new A character will appear every time a
|
||||||
|
// small interval has passed, not just every time the code checks if A is down.
|
||||||
|
bool pop_is_key_just_down(int abskbkey)
|
||||||
|
{
|
||||||
|
assert(0 <= abskbkey);
|
||||||
|
if ( MAX_KEY_NUMBER <= (size_t) abskbkey )
|
||||||
|
return false;
|
||||||
|
if ( keys_pending[abskbkey] )
|
||||||
|
{
|
||||||
|
keys_pending[abskbkey] = false;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &key_handled_last[abskbkey]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( !keys_down[abskbkey] )
|
||||||
|
return false;
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
struct timespec elapsed = timespec_sub(now, key_handled_last[abskbkey]);
|
||||||
|
struct timespec repress_delay = timespec_make(0, 100 * 1000 * 1000);
|
||||||
|
if ( timespec_lt(elapsed, repress_delay) )
|
||||||
|
return false;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &key_handled_last[abskbkey]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read input from the keyboard.
|
||||||
|
void input()
|
||||||
|
{
|
||||||
|
// Read the keyboard input from the user.
|
||||||
|
unsigned termmode = TERMMODE_KBKEY | TERMMODE_SIGNAL | TERMMODE_NONBLOCK;
|
||||||
|
if ( settermmode(0, termmode) )
|
||||||
|
error(1, errno, "settermmode");
|
||||||
|
uint32_t codepoint;
|
||||||
|
ssize_t numbytes;
|
||||||
|
while ( 0 < (numbytes = read(0, &codepoint, sizeof(codepoint))) )
|
||||||
|
{
|
||||||
|
int kbkey = KBKEY_DECODE(codepoint);
|
||||||
|
if( !kbkey )
|
||||||
|
continue;
|
||||||
|
int abskbkey = (kbkey < 0) ? -kbkey : kbkey;
|
||||||
|
if ( MAX_KEY_NUMBER <= (size_t) abskbkey )
|
||||||
|
continue;
|
||||||
|
bool is_key_down_event = 0 < kbkey;
|
||||||
|
if ( !keys_down[abskbkey] && is_key_down_event )
|
||||||
|
keys_pending[abskbkey] = true;
|
||||||
|
keys_down[abskbkey] = is_key_down_event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the game until no longer needed.
|
||||||
|
void mainloop(struct dispd_window* window)
|
||||||
|
{
|
||||||
|
struct dispd_framebuffer* window_fb = dispd_begin_render(window);
|
||||||
|
if ( window_fb )
|
||||||
|
{
|
||||||
|
game_width = dispd_get_framebuffer_width(window_fb);
|
||||||
|
game_height = dispd_get_framebuffer_height(window_fb);
|
||||||
|
dispd_finish_render(window_fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
struct timespec last_frame_time;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &last_frame_time);
|
||||||
|
|
||||||
|
render(window);
|
||||||
|
|
||||||
|
while ( game_running )
|
||||||
|
{
|
||||||
|
struct timespec current_frame_time;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, ¤t_frame_time);
|
||||||
|
|
||||||
|
struct timespec deltatime_ts =
|
||||||
|
timespec_sub(current_frame_time, last_frame_time);
|
||||||
|
float deltatime = deltatime_ts.tv_sec + deltatime_ts.tv_nsec / 1E9f;
|
||||||
|
|
||||||
|
input();
|
||||||
|
update(deltatime);
|
||||||
|
render(window);
|
||||||
|
|
||||||
|
last_frame_time = current_frame_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a display context, run the game, and then cleanly exit.
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if ( !dispd_initialize(&argc, &argv) )
|
||||||
|
error(1, 0, "couldn't initialize dispd library");
|
||||||
|
struct dispd_session* session = dispd_attach_default_session();
|
||||||
|
if ( !session )
|
||||||
|
error(1, 0, "couldn't attach to dispd default session");
|
||||||
|
if ( !dispd_session_setup_game_rgba(session) )
|
||||||
|
error(1, 0, "couldn't setup dispd rgba session");
|
||||||
|
struct dispd_window* window = dispd_create_window_game_rgba(session);
|
||||||
|
if ( !window )
|
||||||
|
error(1, 0, "couldn't create dispd rgba window");
|
||||||
|
|
||||||
|
mainloop(window);
|
||||||
|
|
||||||
|
dispd_destroy_window(window);
|
||||||
|
dispd_detach_session(session);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue