#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <helianthus.h>
Sprite player;
Group walls;
Group boxes;
Group places;
Animation animPlayer;
Animation animWall;
Animation animBox;
Animation animPlace;
Font font;
double speed = 256;
int level = 0;
void loadLevel() {
FILE *f = NULL;
Directory dir = openDirectoryEx("data/levels/sokoban", "", ".level", FALSE, TRUE, FALSE);
if (dir) {
int count = directoryGetCount(dir);
if (count > 0) {
if (level >= count) level = 0;
if (level < 0) level = count - 1;
f = fopen(directoryGetFull(dir, level), "r");
}
closeDirectory(dir);
}
if (!f) {
messageBox("Cannot open level file");
return;
}
groupDestroyEach(walls);
groupDestroyEach(boxes);
groupDestroyEach(places);
int c;
int x = 32;
int y = 32;
int maxX = 0, maxY = 0;
Sprite s;
do {
c = fgetc(f);
if (c == '\n') { y += 64; x = 32; continue; }
if (c == '.') {
s = createSpriteEx(x, y, 10, 10, animPlace);
spriteSetColliderCircle(s, 0, 0, -1);
spriteSetDepth(s, 1);
groupAdd(places, s);
} else
if (c == '#') {
s = createSpriteEx(x, y, 64, 64, animWall);
spriteSetMassLevel(s, 100);
groupAdd(walls, s);
if (maxX < x) maxX = x;
if (maxY < y) maxY = y;
} else
if (c == 'B') {
s = createSpriteEx(x, y, 62, 62, animBox);
spriteSetColliderRectangle(s, 0, 0, 0, -1, -1, 16);
groupAdd(boxes, s);
} else
if (c == '@') {
spriteSetXY(player, x, y);
}
x += 64;
} while (c != EOF);
fclose(f);
windowSetWidth(maxX + 32);
windowSetHeight(maxY + 32);
}
void init() {
background(colorByName("black"));
animPlayer = createAnimation("data/sprite/breadball.png");
animWall = createAnimation("data/sprite/bricks-tile.png");
animBox = createAnimation("data/sprite/box.png");
animPlace = createAnimation("data/sprite/dot.png");
font = createFont("data/fonts/blackcry.ttf");
textFont(font);
player = createSpriteEx(0, 0, 62, 62, animPlayer);
spriteSetColliderCircle(player, 0, 0, -1);
walls = createGroup();
boxes = createGroup();
places = createGroup();
loadLevel();
}
void draw() {
double dt = windowGetFrameTime();
double x = spriteGetX(player);
double y = spriteGetY(player);
double step = speed*dt;
if (keyDown("left")) {
spriteSetMirrorX(player, -1);
spriteSetX(player, x - step);
}
if (keyDown("right")) {
spriteSetMirrorX(player, 1);
spriteSetX(player, x + step);
}
if (keyDown("up")) {
spriteSetY(player, y - step);
}
if (keyDown("down")) {
spriteSetY(player, y + step);
}
if (keyWentDown("r")) {
loadLevel();
}
if (keyWentDown("pageup")) {
--level;
loadLevel();
}
if (keyWentDown("pagedown")) {
++level;
loadLevel();
}
groupCollide(walls, player);
groupCollide(boxes, player);
groupCollideBetween(boxes);
groupCollideGroup(walls, boxes);
drawSprites();
noFill();
stroke(colorByName("white"));
textAlign(HALIGN_CENTER, VALIGN_BOTTOM);
text(windowGetWidth()/2, windowGetHeight() - 10, "R - restart level, PgUp - previous level, PgDown - next level");
}
int main() {
windowSetTitle("Sokoban");
windowSetInit(&init);
windowSetDraw(&draw);
windowSetFrameRateEx(10, 100);
windowRun();
return 0;
}