From 75476da4afcb2335ff004e762aae0078ae3848d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 10 Feb 2020 12:55:15 +0100 Subject: [PATCH] Fix shot collisions --- constants.h | 7 ++++ main.c | 94 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/constants.h b/constants.h index 317f65d..3101c8a 100644 --- a/constants.h +++ b/constants.h @@ -41,6 +41,13 @@ */ #define SFG_MELEE_RANGE 1600 +/** + When a projectile is shot, it'll be offset by this distance (in RCL_Units) + from the shooter. +*/ + +#define SFG_PROJECTILE_SPAWN_OFFSET 256 + /** Player's melee hit range, in RCL_Units (RCL_UNITS_PER_SQUARE means full angle, 180 degrees to both sides). diff --git a/main.c b/main.c index 292cafc..f1c6908 100755 --- a/main.c +++ b/main.c @@ -1637,7 +1637,7 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) ) + RCL_UNITS_PER_SQUARE / 2, dir, 0, - SFG_ELEMENT_COLLISION_DISTANCE + SFG_PROJECTILE_SPAWN_OFFSET ); } } @@ -1842,6 +1842,35 @@ static inline uint8_t SFG_elementCollides( <= SFG_ELEMENT_COLLISION_DISTANCE; } +/** + Checks collision of a projectile with level element at given position. +*/ +uint8_t SFG_projectileCollides(SFG_ProjectileRecord *projectile, + RCL_Unit x, RCL_Unit y, RCL_Unit z) +{ + if (!SFG_elementCollides(x,y,z, + projectile->position[0],projectile->position[1],projectile->position[2])) + return 0; + + if ((projectile->type == SFG_PROJECTILE_EXPLOSION) || + (projectile->type == SFG_PROJECTILE_DUST)) + return 0; + + /* For directional projectiles we only register a collision if its direction + is "towards" the element so that the shooter doesn't get shot by his own + projectile. */ + + RCL_Vector2D projDir, toElement; + + projDir.x = projectile->direction[0]; + projDir.y = projectile->direction[1]; + + toElement.x = x - projectile->position[0]; + toElement.y = y - projectile->position[1]; + + return RCL_vectorsAngleCos(projDir,toElement) >= 0; +} + SFG_getLevelElementSprite( uint8_t elementType, uint8_t *spriteIndex, uint8_t *spriteSize) { @@ -1984,7 +2013,7 @@ void SFG_gameStep() (SFG_player.camera.shear * SFG_GET_PROJECTILE_SPEED_UPS(projectile)) / SFG_CAMERA_MAX_SHEAR_PIXELS, - SFG_ELEMENT_COLLISION_DISTANCE + RCL_CAMERA_COLL_RADIUS + SFG_PROJECTILE_SPAWN_OFFSET ); direction += angleAdd; @@ -2432,12 +2461,12 @@ void SFG_gameStep() uint8_t eliminate = 0; - for (uint8_t j = 0; j < 3; ++j) // projectile outside map? + for (uint8_t j = 0; j < 3; ++j) { pos[j] = p->position[j]; pos[j] += p->direction[j]; - if ( + if ( // projectile outside map? (pos[j] < 0) || (pos[j] >= (SFG_MAP_SIZE * RCL_UNITS_PER_SQUARE))) { @@ -2450,36 +2479,33 @@ void SFG_gameStep() { eliminate = 1; } - else if (SFG_elementCollides( // hits player? - SFG_player.camera.position.x, - SFG_player.camera.position.y, - SFG_player.camera.height, - p->position[0], - p->position[1], - p->position[2] - )) - { - eliminate = 1; - - SFG_playerChangeHealth(-1 * SFG_getDamageValue(attackType)); - } else if ( (p->type != SFG_PROJECTILE_EXPLOSION) && (p->type != SFG_PROJECTILE_DUST)) { + if (SFG_projectileCollides( // collides with player? + p, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height)) + { + eliminate = 1; + SFG_playerChangeHealth(-1 * SFG_getDamageValue(attackType)); + } + // check collision with the map - if ( - (SFG_floorHeightAt(pos[0] / RCL_UNITS_PER_SQUARE,pos[1] / + if (!eliminate && + ((SFG_floorHeightAt(pos[0] / RCL_UNITS_PER_SQUARE,pos[1] / RCL_UNITS_PER_SQUARE) >= pos[2]) || (SFG_ceilingHeightAt(pos[0] / RCL_UNITS_PER_SQUARE,pos[1] / - RCL_UNITS_PER_SQUARE) <= pos[2]) + RCL_UNITS_PER_SQUARE) <= pos[2])) ) eliminate = 1; // check collision with active level elements - + if (!eliminate) // monsters for (uint16_t j = 0; j < SFG_currentLevel.monsterRecordCount; ++j) { @@ -2487,18 +2513,13 @@ void SFG_gameStep() if (SFG_MR_STATE(*m) != SFG_MONSTER_STATE_INACTIVE) { - if ( - SFG_elementCollides( - p->position[0], - p->position[1], - p->position[2], - SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[0]), - SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[1]), - SFG_floorHeightAt( - SFG_MONSTER_COORD_TO_SQUARES(m->coords[0]), - SFG_MONSTER_COORD_TO_SQUARES(m->coords[1])) - ) - ) + if (SFG_projectileCollides(p, + SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[0]), + SFG_MONSTER_COORD_TO_RCL_UNITS(m->coords[1]), + SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(m->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(m->coords[1])) + )) { eliminate = 1; SFG_monsterChangeHealth(m,-1 * SFG_getDamageValue(attackType)); @@ -2518,10 +2539,7 @@ void SFG_gameStep() RCL_Unit y = SFG_ELEMENT_COORD_TO_RCL_UNITS(e->coords[1]); RCL_Unit z = SFG_floorHeightAt(e->coords[0],e->coords[1]); - if ( - SFG_elementCollides(p->position[0],p->position[1],p->position[2], - x,y,z) - ) + if (SFG_projectileCollides(p,x,y,z)) { if ( (e->type == SFG_LEVEL_ELEMENT_BARREL) && @@ -2545,6 +2563,8 @@ void SFG_gameStep() SFG_createExplosion(p->position[0],p->position[1],p->position[2]); else if (p->type == SFG_PROJECTILE_BULLET) SFG_createDust(p->position[0],p->position[1],p->position[2]); + else if (p->type == SFG_PROJECTILE_PLASMA) + SFG_playSoundSafe(4,SFG_distantSoundVolume(pos[0],pos[1],pos[2])); // remove the projectile