dino/obstacle.c
2024-03-07 02:02:03 +03:00

154 lines
4.4 KiB
C

#include "obstacle.h"
ObstacleTypeConfig obstacleTypeConfigs[3] = {
{
.type = CACTUS_SMALL,
.width = 17,
.height = 35,
.yPos = 105,
.multipleSpeed = 4,
.minGap = 120,
.minSpeed = 0,
.collisionBoxesCount = 3,
.collisionBoxes = {
{.x = 0, .y = 7, .width = 5, .height = 27},
{.x = 4, .y = 0, .width = 6, .height = 34},
{.x = 10, .y = 4, .width = 7, .height = 14}
},
.numFrames = 1,
.speedOffset = 0
},
{
.type = CACTUS_LARGE,
.width = 25,
.height = 50,
.yPos = 90,
.multipleSpeed = 7,
.minGap = 120,
.minSpeed = 0,
.collisionBoxesCount = 3,
.collisionBoxes = {
{.x = 0, .y = 12, .width = 7, .height = 38},
{.x = 8, .y = 0, .width = 7, .height = 49},
{.x = 13, .y = 10, .width = 10, .height = 38}
},
.numFrames = 1,
.speedOffset = 0
},
{
.type = PTERODACTYL,
.width = 46,
.height = 40,
.yPos = -1,
.yPosArrSize = 3,
.yPosArr = {100, 75, 50},
.multipleSpeed = 999,
.minGap = 150,
.minSpeed = 8.5,
.collisionBoxesCount = 5,
.collisionBoxes = {
{.x = 15, .y = 15, .width = 16, .height = 5},
{.x = 18, .y = 21, .width = 24, .height = 6},
{.x = 2, .y = 14, .width = 4, .height = 3},
{.x = 6, .y = 10, .width = 4, .height = 7},
{.x = 10, .y = 8, .width = 6, .height = 9}
},
.numFrames = 2,
.frameRate = 1000 / 6,
.speedOffset = 0.8
}
};
int obstacleSpritePosX[3] = { ATLAS_CACTUS_SMALL_X, ATLAS_CACTUS_LARGE_X, ATLAS_PTERODACTYL_X};
int obstacleSpritePosY[3] = { ATLAS_CACTUS_SMALL_Y, ATLAS_CACTUS_LARGE_Y, ATLAS_PTERODACTYL_Y};
void obstacleInit(Obstacle* ob, ObstacleTypeConfig *otc, int dim_width, double gapCoefficient, double speed, int opt_xOffset) {
ob->typeConfig = *otc;
ob->gapCoefficient = gapCoefficient;
ob->size = getRandomNumber(1, OBSTACLE_MAX_OBSTACLE_LENGTH);
ob->remove = false;
ob->xPos = dim_width + opt_xOffset;
ob->yPos = 0;
// For animated obstacles
ob->currentFrame = 0;
ob->timer = 0;
ob->followingObstacleCreated = false;
if (ob->size > 1 && ob->typeConfig.multipleSpeed > speed) { // NOTE what it this?
ob->size = 1;
}
ob->width = ob->typeConfig.width * ob->size;
if (ob->typeConfig.yPos == -1) {
ob->yPos = ob->typeConfig.yPosArr[getRandomNumber(0, ob->typeConfig.yPosArrSize)];
}
else {
ob->yPos = ob->typeConfig.yPos;
}
obstacleDraw(ob);
// Make collision box adjustments,
// Central box is adjusted to the size as one box.
// ____ ______ ________
// _| |-| _| |-| _| |-|
// | |<->| | | |<--->| | | |<----->| |
// | | 1 | | | | 2 | | | | 3 | |
// |_|___|_| |_|_____|_| |_|_______|_|
//
if (ob->size > 1) {
ob->typeConfig.collisionBoxes[1].width = ob->width - ob->typeConfig.collisionBoxes[0].width - ob->typeConfig.collisionBoxes[2].width;
ob->typeConfig.collisionBoxes[2].x = ob->width - ob->typeConfig.collisionBoxes[2].width;
}
// For obstacles that go at a different speed from the horizon
if (ob->typeConfig.speedOffset) {
ob->typeConfig.speedOffset = (double)rand() / RAND_MAX > 0.5 ? ob->typeConfig.speedOffset : -ob->typeConfig.speedOffset;
}
ob->gap = obstacleGetGap(ob, ob->gapCoefficient, speed);
}
void obstacleDraw(const Obstacle *ob) {
int sourceWidth = ob->typeConfig.width;
int sourceHeight = ob->typeConfig.height;
int sourceX = (sourceWidth * ob->size) * (0.5 * ((double)ob->size - 1)) + obstacleSpritePosX[ob->typeConfig.type];
if (ob->currentFrame > 0) {
sourceX += sourceWidth*ob->currentFrame;
}
graphicsBlitAtlasImage(sourceX, obstacleSpritePosY[ob->typeConfig.type], ob->xPos, ob->yPos, sourceWidth*ob->size, sourceHeight, false);
}
void obstacleUpdate(Obstacle *ob, int deltaTime, double speed) {
if (!ob->remove) {
ob->xPos -= floor(((speed + ob->typeConfig.speedOffset)*FPS/1000.)*deltaTime);
}
// Update frames
if (ob->typeConfig.numFrames > 1) {
ob->timer += deltaTime;
if (ob->timer >= ob->typeConfig.frameRate) {
ob->currentFrame = ob->currentFrame == ob->typeConfig.numFrames - 1 ? 0 : ob->currentFrame + 1;
ob->timer = 0;
}
}
obstacleDraw(ob);
if (!obstacleIsVisible(ob)) {
ob->remove = true;
}
}
int obstacleGetGap(const Obstacle *ob, double gapCoefficient, double speed) {
int minGap = round(ob->width * speed + ob->typeConfig.minGap * gapCoefficient);
int maxGap = round(minGap * OBSTACLE_MAX_GAP_COEFFICIENT);
return getRandomNumber(minGap, maxGap);
}
bool obstacleIsVisible(const Obstacle* ob) {
return ob->xPos + ob->width > 0;
}