Skip to content

Instantly share code, notes, and snippets.

@kristianlm
Last active March 16, 2022 18:07
Show Gist options
  • Save kristianlm/5ddf3710779fdfb54a8ce4de2fbde15e to your computer and use it in GitHub Desktop.
Save kristianlm/5ddf3710779fdfb54a8ce4de2fbde15e to your computer and use it in GitHub Desktop.
/gamepad-train-main
/gamepad-train
/gamepad-train.build.sh
/gamepad-train.install.sh
/gamepad-train.link
#include "raylib.h"
#include <math.h>
#include <stdio.h>
typedef struct {
Vector2 pos;
Color color;
} Player;
int load_next(Texture *t);
#ifndef load_next_provided
int load_next(Texture *t) {
static int texnum = 0;
UnloadTexture(*t);
*t = LoadTexture(TextFormat("%d.png", ++texnum));
return 1;
}
#endif
int main() {
int SX = 1920;
int SY = 1080;
Player players[] = {{.pos = {0, 0}, .color = YELLOW},
{.pos = {0, 0}, .color = BLUE},
{.pos = {0, 0}, .color = GREEN},
{.pos = {0, 0}, .color = RED}};
float targetRadius = 0.200;
SetConfigFlags(FLAG_MSAA_4X_HINT);
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(SX, SY, "blame photo game [ floating ]");
InitAudioDevice();
HideCursor();
Sound fxSuccess = LoadSound("success.mp3");
Sound fxTick = LoadSound("tick.wav");
SetSoundVolume(fxTick, 0.25);
Texture tex = {};
load_next(&tex);
SetTargetFPS(60);
double lastTick = GetTime();
Vector2 target = {1, 1};
bool debug = 0, quit = 0;
while(!WindowShouldClose() && !quit) {
bool next = 0; // next picture?
SX = GetScreenWidth();
SY = GetScreenHeight();
double now = GetTime();
double delay = fmin(1.5,
fmax(0.15,
(fabs(players[0].pos.x - target.x) +
fabs(players[0].pos.y - target.y))));
if(now - lastTick > delay) {
PlaySound(fxTick);
lastTick = now;
}
if(IsKeyPressed(KEY_N)) next = true;
if(IsKeyPressed(KEY_SPACE)) PlaySound(fxTick);
if(IsKeyPressed(KEY_Q)) quit = true;
if(IsKeyPressed(KEY_H)) debug = !debug;
BeginDrawing(); {
ClearBackground(BLACK);
Vector2 scale2 = {(float)SX / tex.width, (float)SY / tex.height};
float scale = scale2.x > scale2.y ? scale2.y : scale2.x;
Vector2 pos = {
(SX - scale*tex.width)/2,
(SY - scale*tex.height)/2};
DrawTextureEx(tex, pos, 0, scale, WHITE);
Color targetColor = (Color){255,255,0,240};
Color borderColor = (now - lastTick) > 0.05
? (Color){0, 0, 0, 100}
: (Color){255, 255, 255, 200};
Vector2 center = (Vector2){target.x * SX, target.y * SY};
DrawCircleSector(center, targetRadius * SY + 100, 0, 360, 60, borderColor);
DrawCircleSector(center, targetRadius * SY + 0, 0, 360, 50, targetColor);
if(debug) {
DrawText(TextFormat("%d %.1f", GetFPS(), GetTime()), 10, 0, 50, PURPLE);
DrawText(TextFormat("delay=%f %f,%f", delay, players[0].pos.x, players[0].pos.y), 10, 50, 50, YELLOW);
}
if(sqrt(pow(SX * (players[0].pos.x - target.x), 2) +
pow(SY * (players[0].pos.y - target.y), 2)) < targetRadius * SY) {
next = true;
int rnd = GetRandomValue(0, 3);
switch(rnd) {
case 0: target = (Vector2){0, 0}; break;
case 1: target = (Vector2){0, 1}; break;
case 2: target = (Vector2){1, 0}; break;
case 3: target = (Vector2){1, 1}; break;
}
players[0].pos.x = (1 - target.x);
players[0].pos.y = (1 - target.y);
}
int pn = 0; // todo: for-loop for each controller
Vector2 *p = &players[pn].pos;
float dx=0, dy=0;
if(IsGamepadAvailable(pn)) {
dx += GetGamepadAxisMovement(pn, GAMEPAD_AXIS_LEFT_X);
dy += GetGamepadAxisMovement(pn, GAMEPAD_AXIS_LEFT_Y);
dx += GetGamepadAxisMovement(pn, GAMEPAD_AXIS_RIGHT_X);
dy += GetGamepadAxisMovement(pn, GAMEPAD_AXIS_RIGHT_Y);
}
if(dx < -1) dx = -1; if(dx > 1) dx = 1;
if(dy < -1) dy = -1; if(dy > 1) dy = 1;
if(pn == 0) { // keyboard input too for player 0
if(IsKeyDown(KEY_W)) dy = -1;
if(IsKeyDown(KEY_A)) dx = -1;
if(IsKeyDown(KEY_S)) dy = 1;
if(IsKeyDown(KEY_D)) dx = 1;
}
p->x += 0.01 * (dx * dx * dx);
p->y += 0.01 * (dy * dy * dy);
if(p->x < 0) p->x = 0; if(p->x > 1) p->x = 1;
if(p->y < 0) p->y = 0; if(p->y > 1) p->y = 1;
DrawRing((Vector2){p->x * SX, p->y * SY}, 110-4, 110+20, 0, 360, 30, (Color){40, 40, 40, 255});
DrawCircle(p->x * SX, p->y * SY, 110, (Color){40, 40, 40, 150});
DrawCircle(p->x * SX, p->y * SY, 60, players[pn].color);
if(next) {
PlaySound(fxSuccess);
if(!load_next(&tex)) {
quit = true;
}
}
} EndDrawing();
}
UnloadTexture(tex);
UnloadSound(fxTick);
CloseAudioDevice();
CloseWindow();
return 0;
}
;; -*- scheme -*-
((author "Kristian Lein-Mathisen")
(license "public domain")
(category graphics)
(test-dependencies)
(synopsis "joystick practice with images and sound")
(components (program gamepad-train
(csc-options "-O3")
(link-options "-L" "-lraylib")
(source "gamepad-train.scm")
(source-dependencies "gamepad-core.c")
(linkage static))))
;;; a chicken wrapper around the demo for these reasons:
;;; - raylib can't load jpg files
;;; - i don't want to shuffle-sort the list of files in C
(import chicken.string chicken.foreign chicken.file
chicken.condition chicken.sort chicken.random
chicken.process-context chicken.pathname
srfi-4 stb-image)
;; go to our asset folder (TODO: do this properly?)
(set! (current-directory)
(pathname-directory (executable-pathname)))
(foreign-declare "
#define main my_main
#define load_next_provided
#include \"gamepad-core.c\"
#undef main
")
(define unload-texture
(foreign-lambda* void (((c-pointer "Texture") texture))
"UnloadTexture(*texture);"))
;; raylib's LoadTexture doesn't support jpg, so we work around that
;; here by using, ironically, a version of stb-image with jpg support.
(define (load-texture! texture filename)
(print "LOADING texture " texture " " filename)
(receive (pixels w h c)
(parameterize
((current-exception-handler
(let ((ceh (current-exception-handler)))
(lambda (e)
(print "error: could not load " filename)
(ceh e)))))
(with-input-from-file filename
(lambda () (read-image channels: 3))
#:binary))
(unless (= c 3) (error "internal error, expecting 3 channels" c))
((foreign-lambda* void
(((c-pointer "Texture") texture)
(u8vector pixels)
(int w)
(int h))
"
*texture = LoadTextureFromImage((Image){
.data = pixels, .width = w, .height = h, .mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8});
")
texture pixels w h)))
(when (null? (command-line-arguments))
(print "usage: photo1 [photo2 ] ...")
(exit 1))
(define images
(sort (command-line-arguments)
(lambda (a b) (zero? (pseudo-random-integer 2)))))
(print "random-shuffled " (length images) " input images")
(define-external
(load_next ((c-pointer "Texture") texture))
int
(if (pair? images)
(let ((filename (car images)))
(set! images (cdr images))
(unload-texture texture)
(load-texture! texture filename)
#t)
#f))
((foreign-safe-lambda void "my_main"))
all:
csc -L -lraylib -O2 gamepad-train.scm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment