void Game::moveMissiles() { int i; i = 0; while (i < _missileId) { _board.setMatriceValueAt(_missile[i].getPosX(), _missile[i].getPosY(), 0); switch(_missile[i].getDirection()) { case RIGHT : _missile[i].goRight(); break; case LEFT : _missile[i].goLeft(); break; } if (_missile[i].getPosX() > _win.getW() || _missile[i].getPosX() < 0) deleteEntity(_missile[i]); else if (_missile[i].getPosY() > _win.getW() || _missile[i].getPosY() < 0) deleteEntity(_missile[i]); else if (!checkIfCollision(_missile[i])) { _board.setMatriceValueAt(_missile[i].getPosX(), _missile[i].getPosY(), &_missile[i]); i++; } } }
void EntityManager::clear() { for (auto entityEntry : entityExistence) { deleteEntity(entityEntry.first); } entityExistence.clear(); }
void deleteActor(character *chr) { item *lodgedItem = getItemLodgedInActor(chr); if (chr == getPlayer()) { killPlayer(); } deleteEntity(getWorld(), chr->entityId); if (lodgedItem) { lodgedItem->itemFlags ^= IS_LODGED; lodgedItem->lodgedInActor = NULL; lodgedItem->x = chr->x; lodgedItem->y = chr->y; } if (chr->itemLight) { deleteDynamicLight(chr->itemLight); chr->itemLight = NULL; } if (chr == CHARACTERS) { CHARACTERS = chr->next; } else { chr->prev->next = chr->next; if (chr->next) { chr->next->prev = chr->prev; } } free(chr); }
void CGameEngine::cleanEntityToDelete() { while(!m_entityToDelete.empty()) { deleteEntity(m_entityToDelete.top()); m_entityToDelete.pop(); } }
void CObjectViewer::deleteEntities() { for (EIT eit = _Entities.begin(); eit != _Entities.end(); ++eit) { CEntity &entity = (*eit).second; deleteEntity(entity); } _Entities.clear(); }
void Game::moveEnemies() { int i; i = 0; while (i < _enemyId) { deleteShip(_enemy[i]); _enemy[i].goLeft(); if (_enemy[i].getPosX() < 0) _win.renderLose(); if (_enemy[i].getPosY() > _win.getH() || _enemy[i].getPosY() < 0) deleteEntity(_enemy[i]); if (!checkIfCollision(_enemy[i])) drawShip(_enemy[i]); i++; } }
void ProjectileCollideSystem::update() { for(int subID = 0; subID < subscribedEntities[0].size(); subID++) { //Get projectile component Entity * projectileEnt = entities[subscribedEntities[0][subID]]; ColliderComponent* projectileCollideComp = static_cast<ColliderComponent*>(projectileEnt->getComponent(ColliderComponent::getStaticID())); WorldComponent * projectileWorldComp = static_cast<WorldComponent*>(projectileEnt->getComponent(WorldComponent::getStaticID())); PhysicsComponent* projectilePhysicsComp = static_cast<PhysicsComponent*>(projectileEnt->getComponent(PhysicsComponent::getStaticID())); //Check projectile for collisions for(int i = 0; i < projectileCollideComp->collisionData.size(); i++) { std::shared_ptr<CollisionPair> collision = projectileCollideComp->collisionData[i]; int projectilePairID = collision->getCollisionPairID(subscribedEntities[0][subID]);//Projectile's CollisionPairID int collidingPairID = collision->getOppositePairID(projectilePairID);//The Colliding Ent's CollisionPairID Entity * collidingEnt = entities[collision->getCollisionEntityID(collidingPairID)]; //The Colliding Entity //Check the type of the collided entity and perform action if(collidingEnt->hasComponent(TerrainComponent::getStaticID())) { deleteEntity(projectileEnt->entityID); } if(collidingEnt->hasComponent(PhysicsComponent::getStaticID()) && !collidingEnt->hasComponent(PlayerComponent::getStaticID())) { glm::vec2 col = collision->getMinimumTranslation(projectilePairID); PhysicsComponent* physicsComp = static_cast<PhysicsComponent*>(collidingEnt->getComponent(PhysicsComponent::getStaticID())); //Should 1. Be conserving energy //Should 2. Be making sure the velocity is transfered correctly //http://gafferongames.com/virtual-go/collision-response-and-coulomb-friction/ float j = -(1+physicsComp->coefficientRestitution)*glm::dot(projectilePhysicsComp->velocity*projectilePhysicsComp->mass,glm::normalize(col)); //projectiles impulse float impulseMag = glm::max(j, 0.0f); //Logger()<<impulseMag<<std::endl; physicsComp->impulse(impulseMag*glm::normalize(-col)); projectilePhysicsComp->impulse(impulseMag*glm::normalize(col)); } } } }
int Game::checkIfCollision(AGameEntity & entity) { AGameEntity *result; result = _board.getMatriceValueAt(entity.getPosX(), entity.getPosY()); if (!result) return 0; switch (result->getType()) { case MISSILE: if (entity.getType() != MISSILE) { deleteEntity(*result); deleteEntity(entity); return 1; } break ; case ENEMY : if (entity.getType() == MISSILE) { if (static_cast<Missile &>(entity).getDirection() == RIGHT) { deleteEntity(*result); deleteEntity(entity); _win.incScore(); return 1; } return 0; } else deleteEntity(*result); return 1; case PLAYER : if (static_cast<Missile &>(entity).getDirection() == RIGHT) return 0; loseHp(static_cast<Player &>(*result)); deleteEntity(entity); return 1; case 0: return 0; } return 0; }
int ClientInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QMainWindow::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: sendMessage(); break; case 1: chat((*reinterpret_cast< CLID(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2])),(*reinterpret_cast< QString(*)>(_a[3])),(*reinterpret_cast< ENUM_TYPE(*)>(_a[4]))); break; case 2: changeServerInformations((*reinterpret_cast< ServerInformations(*)>(_a[1]))); break; case 3: changeClientID((*reinterpret_cast< CLID(*)>(_a[1]))); break; case 4: changeClientNickname((*reinterpret_cast< CLID(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 5: showError((*reinterpret_cast< ENUM_TYPE(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 6: changeGameMaster((*reinterpret_cast< CLID(*)>(_a[1]))); break; case 7: clientVoted((*reinterpret_cast< CLID(*)>(_a[1])),(*reinterpret_cast< CLID(*)>(_a[2]))); break; case 8: connectionEtablished(); break; case 9: connectionLost(); break; case 10: diceRolled((*reinterpret_cast< CLID(*)>(_a[1])),(*reinterpret_cast< quint16(*)>(_a[2])),(*reinterpret_cast< quint16(*)>(_a[3]))); break; case 11: sanctionned((*reinterpret_cast< CLID(*)>(_a[1])),(*reinterpret_cast< ENUM_TYPE(*)>(_a[2])),(*reinterpret_cast< QString(*)>(_a[3]))); break; case 12: rollDice(); break; case 13: rollSpecialDice(); break; case 14: serverName((*reinterpret_cast< QString(*)>(_a[1]))); break; case 15: motdChanged((*reinterpret_cast< QString(*)>(_a[1]))); break; case 16: gameLaunched(); break; case 17: setTitle(); break; case 18: playSound((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 19: updatePlayerList(); break; case 20: clientJoined((*reinterpret_cast< CLID(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 21: clientLeft((*reinterpret_cast< CLID(*)>(_a[1]))); break; case 22: updateGMLabel(); break; case 23: updateGMPanel(); break; case 24: { bool _r = addLanguage(); if (_a[0]) *reinterpret_cast< bool*>(_a[0]) = _r; } break; case 25: { bool _r = addLanguage((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2]))); if (_a[0]) *reinterpret_cast< bool*>(_a[0]) = _r; } break; case 26: languageListMenu((*reinterpret_cast< const QPoint(*)>(_a[1]))); break; case 27: { bool _r = removeLanguage((*reinterpret_cast< const QString(*)>(_a[1]))); if (_a[0]) *reinterpret_cast< bool*>(_a[0]) = _r; } break; case 28: removeLanguageMenu(); break; case 29: importLanguageList(); break; case 30: sendLanguageList(); break; case 31: { CLID _r = CLIDFromString((*reinterpret_cast< const QString(*)>(_a[1]))); if (_a[0]) *reinterpret_cast< CLID*>(_a[0]) = _r; } break; case 32: switchConnectionState(); break; case 33: openSettings(); break; case 34: openSoundsGUI(); break; case 35: aboutUs(); break; case 36: aboutServer(); break; case 37: openMapEditor(); break; case 38: clearMapEditor(); break; case 39: mapFlare(); break; case 40: resetData(); break; case 41: setCSS((*reinterpret_cast< const QString(*)>(_a[1]))); break; case 42: setCSS(); break; case 43: setInterface((*reinterpret_cast< const QString(*)>(_a[1]))); break; case 44: setInterface(); break; case 45: playerListMenu((*reinterpret_cast< const QPoint(*)>(_a[1]))); break; case 46: actionKick(); break; case 47: actionBan(); break; case 48: actionVoteGM(); break; case 49: actionChangeGM(); break; case 50: refresh(); break; case 51: textChanged(); break; case 52: narrationChanged((*reinterpret_cast< QString(*)>(_a[1]))); break; case 53: syncSoundLibs((*reinterpret_cast< QList<SoundLibInformations>(*)>(_a[1]))); break; case 54: syncLanguagesList((*reinterpret_cast< QList<QPair<QString,QString> >(*)>(_a[1]))); break; case 55: syncDictionariesList((*reinterpret_cast< QStringList(*)>(_a[1]))); break; case 56: requestScriptDownload((*reinterpret_cast< QString(*)>(_a[1]))); break; case 57: sendScriptToServer((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 58: deleteScript((*reinterpret_cast< QString(*)>(_a[1]))); break; case 59: renameScript((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 60: makeEntity((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 61: deleteEntity((*reinterpret_cast< const QString(*)>(_a[1]))); break; case 62: injectCode((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 63: scriptToGMMsg((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 64: scriptToOwnerMsg((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 65: scriptActionMsg((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 66: scriptToPlayerMsg((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 67: scriptMsg((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 68: scriptError((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; case 69: sendMapToServer((*reinterpret_cast< const MapInformations*const(*)>(_a[1])),(*reinterpret_cast< const QMap<QString,RSID>(*)>(_a[2]))); break; case 70: addDictionnary(); break; case 71: saveGame(); break; case 72: loadGame(); break; case 73: VOIPRemoveClient(); break; case 74: VOIPAddClient(); break; case 75: VOIPClientVolume(); break; case 76: dataPerSecond((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; default: ; } _id -= 77; } return _id; }
INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) { GameWorldState *world = GET_STATE_DATA(state, &state->persistentArena, GameWorldState); if (!common_isSet(world->flags, gameworldstateflags_init)) { #ifdef DENGINE_DEBUG { u8 *data = (u8 *)world; for (i32 i = 0; i < sizeof(GameWorldState); i++) ASSERT(data[i] == 0); } #endif world->pixelsPerMeter = 70.0f; MemoryIndex entityArenaSize = (MemoryIndex)((f32)memory->transientSize * 0.5f); u8 *arenaBase = state->transientArena.base + state->transientArena.size; memory_arenaInit(&world->entityArena, arenaBase, entityArenaSize); world->camera.min = V2(0, 0); world->camera.max = state->renderer.size; world->size = state->renderer.size; world->entityListSize = 1024; world->entityList = MEMORY_PUSH_ARRAY(&world->entityArena, world->entityListSize, Entity); { // Init null entity Entity *nullEntity = &world->entityList[world->entityIndex++]; nullEntity->id = world->entityIdCounter++; } { // Init asteroid entities world->numAsteroids = 15; } { // Init audio renderer world->numAudioRenderers = 8; world->audioRenderer = MEMORY_PUSH_ARRAY( &world->entityArena, world->numAudioRenderers, AudioRenderer); } { // Global Collision Rules setCollisionRule(world, entitytype_ship, entitytype_asteroid_small, TRUE); setCollisionRule(world, entitytype_ship, entitytype_asteroid_medium, TRUE); setCollisionRule(world, entitytype_ship, entitytype_asteroid_large, TRUE); setCollisionRule(world, entitytype_bullet, entitytype_asteroid_small, TRUE); setCollisionRule(world, entitytype_bullet, entitytype_asteroid_medium, TRUE); setCollisionRule(world, entitytype_bullet, entitytype_asteroid_large, TRUE); } world->numStarP = 100; world->starPList = MEMORY_PUSH_ARRAY(&world->entityArena, world->numStarP, v2); world->starMinOpacity = 0.25f; for (i32 i = 0; i < world->numStarP; i++) { i32 randX = rand() % (i32)world->size.x; i32 randY = rand() % (i32)world->size.y; world->starPList[i] = V2i(randX, randY); } world->flags |= gameworldstateflags_init; world->scoreMultiplier = 5; world->scoreMultiplierBarTimer = 0.0f; world->scoreMultiplierBarThresholdInS = 2.0f; } if (common_isSet(world->flags, gameworldstateflags_level_started)) { Font *arial40 = asset_fontGet(&state->assetManager, "Arial", 40); Renderer *renderer = &state->renderer; /* Render scores onto screen */ v2 stringP = V2((renderer->size.w * 0.5f), renderer->size.h - arial40->size); char gamePointsString[COMMON_ITOA_MAX_BUFFER_32BIT] = {0}; common_itoa(world->score, gamePointsString, ARRAY_COUNT(gamePointsString)); renderer_stringFixedCentered(renderer, &state->transientArena, arial40, gamePointsString, stringP, V2(0, 0), 0, V4(1.0f, 1.0f, 1.0f, 1.0f), 1, 0); /* Render multiplier accumulator bar onto screen */ v2 stringDim = asset_fontStringDimInPixels(arial40, gamePointsString); v2 multiplierOutlineSize = V2(renderer->size.w * 0.5f, stringDim.h * 0.25f); v2 multiplierOutlineP = V2(renderer->size.w * 0.5f, stringP.h); multiplierOutlineP.x -= (multiplierOutlineSize.w * 0.5f); multiplierOutlineP.y -= stringDim.h * 1.5f; renderer_rectFixedOutline( renderer, multiplierOutlineP, multiplierOutlineSize, V2(0, 0), 2, 0, NULL, V4(0.2f, 0.3f, 0.8f, 1.0f), 2, renderflag_no_texture); f32 progressNormalised = world->scoreMultiplierBarTimer / world->scoreMultiplierBarThresholdInS; renderer_rectFixed(renderer, multiplierOutlineP, V2(multiplierOutlineSize.w * progressNormalised, multiplierOutlineSize.h), V2(0, 0), 0, NULL, V4(0.2f, 0.3f, 0.8f, 1.0f), 1, renderflag_no_texture); /* Render multiplier counter hud onto screen */ v2 multiplierHudP = V2(0, 0.05f * renderer->size.h); v2 multiplierHudSize = V2((arial40->maxSize.w * 3.5f), arial40->fontHeight * 1.2f); renderer_rectFixed(renderer, multiplierHudP, multiplierHudSize, V2(0, 0), 0, NULL, V4(1, 1, 1, 0.1f), 2, renderflag_no_texture); /* Render multiplier counter string to hud */ char multiplierToString[COMMON_ITOA_MAX_BUFFER_32BIT + 1] = {0}; common_itoa(world->scoreMultiplier, multiplierToString + 1, ARRAY_COUNT(multiplierToString) - 1); multiplierToString[0] = 'x'; v2 multiplierToStringP = multiplierHudP; multiplierToStringP = v2_add(multiplierToStringP, v2_scale(multiplierHudSize, 0.5f)); renderer_stringFixedCentered( renderer, &state->transientArena, arial40, multiplierToString, multiplierToStringP, V2(0, 0), 0, V4(1.0f, 1.0f, 1.0f, 1.0f), 3, 0); /* Process multiplier bar updates */ if (!common_isSet(world->flags, gameworldstateflags_player_lost)) { f32 barTimerPenalty = 1.0f; if (world->timeSinceLastShot < 1.5f) { barTimerPenalty = 0.1f; } world->scoreMultiplierBarTimer += (barTimerPenalty * dt); world->timeSinceLastShot += dt; if (world->scoreMultiplierBarTimer > world->scoreMultiplierBarThresholdInS) { world->scoreMultiplierBarTimer = 0; world->scoreMultiplier++; if (world->scoreMultiplier > 9999) world->scoreMultiplier = 9999; } } } if (common_isSet(world->flags, gameworldstateflags_player_lost)) { Font *arial40 = asset_fontGet(&state->assetManager, "Arial", 40); char *gameOver = "Game Over"; v2 gameOverP = v2_scale(state->renderer.size, 0.5f); renderer_stringFixedCentered( &state->renderer, &state->transientArena, arial40, "Game Over", gameOverP, V2(0, 0), 0, V4(1, 1, 1, 1), 0, 0); v2 gameOverSize = asset_fontStringDimInPixels(arial40, gameOver); v2 replayP = V2(gameOverP.x, gameOverP.y - (gameOverSize.h * 1.2f)); renderer_stringFixedCentered( &state->renderer, &state->transientArena, arial40, "Press enter to play again or backspace to return to menu", replayP, V2(0, 0), 0, V4(1, 1, 1, 1), 0, 0); if (platform_queryKey(&state->input.keys[keycode_enter], readkeytype_one_shot, 0.0f)) { // TODO(doyle): Extract score init default values to some game // definitions file world->score = 0; world->scoreMultiplier = 5; world->scoreMultiplierBarTimer = 0.0f; world->scoreMultiplierBarThresholdInS = 2.0f; addPlayer(world); world->flags ^= gameworldstateflags_player_lost; } else if (platform_queryKey(&state->input.keys[keycode_backspace], readkeytype_one_shot, 0.0f)) { common_memset((u8 *)world, 0, sizeof(*world)); state->currState = appstate_StartMenuState; return; } } for (u32 i = world->asteroidCounter; i < world->numAsteroids; i++) addAsteroid(world, (rand() % asteroidsize_count)); Radians starRotation = DEGREES_TO_RADIANS(45.0f); v2 starSize = V2(2, 2); ASSERT(world->starMinOpacity >= 0.0f && world->starMinOpacity <= 1.0f); f32 opacityFadeRateInS = 0.5f; if (world->starFadeAway) { opacityFadeRateInS *= -1.0f; } if (world->starOpacity > 1.0f) { world->starOpacity = 1.0f; world->starFadeAway = TRUE; } else if (world->starOpacity < world->starMinOpacity) { world->starOpacity = world->starMinOpacity; world->starFadeAway = FALSE; } world->starOpacity += (opacityFadeRateInS * dt); DEBUG_PUSH_VAR("Star Opacity: %5.2f", world->starOpacity, "f32"); for (i32 i = 0; i < world->numStarP; i++) { world->starPList[i] = v2_add(world->starPList[i], V2(4.0f * dt, 0)); world->starPList[i] = wrapPAroundBounds( world->starPList[i], math_rectCreate(V2(0, 0), world->size)); renderer_rect(&state->renderer, world->camera, world->starPList[i], starSize, V2(0, 0), starRotation, NULL, V4(0.8f, 0.8f, 0.8f, world->starOpacity), 0, renderflag_no_texture | renderflag_wireframe); } #ifdef DENGINE_DEBUG if (platform_queryKey(&state->input.keys[keycode_left_square_bracket], readkeytype_repeat, 0.2f)) { addAsteroid(world, (rand() % asteroidsize_count)); } #endif ASSERT(world->entityList[0].id == NULL_ENTITY_ID); for (i32 i = 1; i < world->entityIndex; i++) { Entity *entity = &world->entityList[i]; ASSERT(entity->type != entitytype_invalid); v2 pivotPoint = {0}; f32 ddPSpeedInMs = 0; v2 ddP = {0}; if (entity->type == entitytype_ship) { if (platform_queryKey(&state->input.keys[keycode_up], readkeytype_repeat, 0.0f)) { // TODO(doyle): Renderer creates upfacing triangles by default, // but we need to offset rotation so that our base "0 degrees" // is right facing for trig to work Radians rotation = DEGREES_TO_RADIANS((entity->rotation + 90.0f)); v2 direction = V2(math_cosf(rotation), math_sinf(rotation)); ddP = direction; AudioVorbis *thrust = asset_vorbisGet(&state->assetManager, "thrust"); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, thrust, 3); if (audioRenderer) { audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, thrust, 1); } } if (platform_queryKey(&state->input.keys[keycode_space], readkeytype_one_shot, KEY_DELAY_NONE)) { addBullet(world, entity); if (world->timeSinceLastShot >= 0) { world->timeSinceLastShot = 0; f32 multiplierPenalty = -2.0f; world->timeSinceLastShot += multiplierPenalty; } AudioVorbis *fire = asset_vorbisGet(&state->assetManager, "fire"); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, fire, 2); if (audioRenderer) { // TODO(doyle): Atm transient arena is not used, this is // just to fill out the arguments audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, fire, 1); } } Degrees rotationsPerSecond = 180.0f; if (platform_queryKey(&state->input.keys[keycode_left], readkeytype_repeat, 0.0f)) { entity->rotation += (rotationsPerSecond)*dt; } if (platform_queryKey(&state->input.keys[keycode_right], readkeytype_repeat, 0.0f)) { entity->rotation -= (rotationsPerSecond)*dt; } entity->rotation = (f32)((i32)entity->rotation); ddPSpeedInMs = 25; DEBUG_PUSH_VAR("Pos: %5.2f, %5.2f", entity->pos, "v2"); DEBUG_PUSH_VAR("Velocity: %5.2f, %5.2f", entity->dP, "v2"); DEBUG_PUSH_VAR("Rotation: %5.2f", entity->rotation, "f32"); DEBUG_PUSH_VAR("TimeSinceLastShot: %5.2f", world->timeSinceLastShot, "f32"); renderer_rect(&state->renderer, world->camera, entity->pos, V2(5, 5), V2(0, 0), DEGREES_TO_RADIANS(entity->rotation), NULL, V4(1.0f, 1.0f, 1.0f, 1.0f), 0, renderflag_no_texture); } else if (entity->type >= entitytype_asteroid_small && entity->type <= entitytype_asteroid_large) { i32 randValue = rand(); // NOTE(doyle): If it is a new asteroid with no dp set, we need to // set a initial dp for it to move from. v2 localDp = {0}; if ((i32)entity->dP.x == 0 && (i32)entity->dP.y == 0) { enum Direction direction = randValue % direction_count; switch (direction) { case direction_north: case direction_northwest: { localDp.x = 1.0f; localDp.y = 1.0f; } break; case direction_west: case direction_southwest: { localDp.x = -1.0f; localDp.y = -1.0f; } break; case direction_south: case direction_southeast: { localDp.x = 1.0f; localDp.y = -1.0f; } break; case direction_east: case direction_northeast: { localDp.x = 1.0f; localDp.y = 1.0f; } break; default: { ASSERT(INVALID_CODE_PATH); } break; } } // NOTE(doyle): Otherwise, if it has pre-existing dp, maintain our // direction by extrapolating from it's current dp else { if (entity->dP.x >= 0) localDp.x = 1.0f; else localDp.x = -1.0f; if (entity->dP.y >= 0) localDp.y = 1.0f; else localDp.y = -1.0f; } /* NOTE(doyle): We compare current dP with the calculated dP. In the event we want to artificially boost the asteroid, we set a higher dP on creation, which will have a higher dP than the default dP we calculate. So here we choose to keep it until it decays enough that the default dP of the asteroid is accepted. */ v2 newDp = v2_scale(localDp, world->pixelsPerMeter * 1.5f); f32 newDpSum = ABS(newDp.x) + ABS(newDp.y); f32 oldDpSum = ABS(entity->dP.x) + ABS(entity->dP.y); if (newDpSum > oldDpSum) { entity->dP = newDp; } } else if (entity->type == entitytype_bullet) { if (!math_rectContainsP(world->camera, entity->pos)) { deleteEntity(world, i--); continue; } Radians rotation = DEGREES_TO_RADIANS((entity->rotation + 90.0f)); v2 localDp = V2(math_cosf(rotation), math_sinf(rotation)); entity->dP = v2_scale(localDp, world->pixelsPerMeter * 5); } else if (entity->type == entitytype_particle) { f32 diff = entity->color.a - 0.1f; if (diff < 0.01f) { deleteEntity(world, i--); continue; } f32 divisor = MAX(entity->particleInitDp.x, entity->particleInitDp.y); f32 maxDp = MAX(entity->dP.x, entity->dP.y); entity->color.a = maxDp / divisor; } entity->pos = wrapPAroundBounds(entity->pos, math_rectCreate(V2(0, 0), world->size)); /* Loop entity around world */ i32 collisionIndex = moveEntity(world, &state->transientArena, entity, i, ddP, dt, ddPSpeedInMs); v4 collideColor = {0}; if (collisionIndex != -1) { ASSERT(collisionIndex < world->entityIndex); Entity *collideEntity = &world->entityList[collisionIndex]; Entity *colliderA; Entity *colliderB; if (collideEntity->type < entity->type) { colliderA = collideEntity; colliderB = entity; } else { colliderA = entity; colliderB = collideEntity; } // Assumptions made that the collision detect system relies on ASSERT(entitytype_ship < entitytype_asteroid_small); ASSERT(entitytype_asteroid_small < entitytype_asteroid_medium); ASSERT(entitytype_asteroid_medium < entitytype_asteroid_large); ASSERT(entitytype_asteroid_large < entitytype_bullet); ASSERT(entitytype_asteroid_small + 1 == entitytype_asteroid_medium); ASSERT(entitytype_asteroid_medium + 1 == entitytype_asteroid_large); if (colliderA->type >= entitytype_asteroid_small && colliderA->type <= entitytype_asteroid_large) { f32 numParticles = 4; if (colliderA->type == entitytype_asteroid_medium) { AsteroidSpec spec = {0}; spec.pos = colliderA->pos; spec.dP = v2_scale(colliderA->dP, -2.0f); addAsteroidWithSpec(world, asteroidsize_small, &spec); numParticles = 8; world->score += (10 * world->scoreMultiplier); } else if (colliderA->type == entitytype_asteroid_large) { AsteroidSpec spec = {0}; spec.pos = colliderA->pos; spec.dP = v2_scale(colliderA->dP, -4.0f); addAsteroidWithSpec(world, asteroidsize_medium, &spec); spec.dP = v2_perpendicular(spec.dP); addAsteroidWithSpec(world, asteroidsize_small, &spec); spec.dP = v2_perpendicular(colliderA->dP); addAsteroidWithSpec(world, asteroidsize_small, &spec); numParticles = 16; world->score += (20 * world->scoreMultiplier); } else { world->score += (5 * world->scoreMultiplier); } for (i32 i = 0; i < numParticles; i++) { { // Add particles Entity *particle = &world->entityList[world->entityIndex++]; particle->id = world->entityIdCounter++; particle->pos = colliderA->pos; particle->size = V2(4.0f, 4.0f); i32 randValue = rand(); Radians rotation = DEGREES_TO_RADIANS((randValue % 360)); v2 randDirectionVec = V2(math_cosf(rotation), math_sinf(rotation)); i32 particleDpLimit = 8; f32 randDpMultiplier = (f32)(randValue % particleDpLimit) + 1; v2 newDp = v2_scale(colliderA->dP, randDpMultiplier); newDp = v2_hadamard(newDp, randDirectionVec); particle->dP = newDp; particle->particleInitDp = newDp; particle->offset = v2_scale(particle->size, -0.5f); particle->hitbox = particle->size; particle->rotation = 0; particle->renderMode = rendermode_polygon; if (!world->particleVertexCache) { world->particleVertexCache = MEMORY_PUSH_ARRAY(&world->entityArena, 4, v2); world->particleVertexCache[0] = V2(0, particle->size.h); world->particleVertexCache[1] = V2(0, 0); world->particleVertexCache[2] = V2(particle->size.w, 0); world->particleVertexCache[3] = particle->size; } particle->vertexPoints = world->particleVertexCache; particle->numVertexPoints = 4; particle->type = entitytype_particle; particle->color = V4(1.0f, 0.0f, 0, 1.0f); } } ASSERT(colliderB->type == entitytype_bullet); deleteEntity(world, collisionIndex); deleteEntity(world, i--); world->asteroidCounter--; ASSERT(world->asteroidCounter >= 0); char *sound; i32 choice = rand() % 3; if (choice == 0) { sound = "bang_small"; } else if (choice == 1) { sound = "bang_medium"; } else { sound = "bang_large"; } AudioVorbis *explode = asset_vorbisGet(&state->assetManager, sound); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, explode, 3); if (audioRenderer) { audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, explode, 1); } continue; } else if (colliderA->type == entitytype_ship) { if (colliderB->type >= entitytype_asteroid_small && colliderB->type <= entitytype_asteroid_large) { world->flags |= gameworldstateflags_player_lost; if (collideEntity->type == entitytype_ship) { deleteEntity(world, collisionIndex); } else { deleteEntity(world, i--); } AudioVorbis *explode = asset_vorbisGet(&state->assetManager, "bang_large"); AudioRenderer *audioRenderer = getFreeAudioRenderer(world, explode, 3); if (audioRenderer) { audio_vorbisPlay(&state->transientArena, &state->audioManager, audioRenderer, explode, 1); } continue; } } } RenderFlags flags = renderflag_wireframe | renderflag_no_texture; renderer_entity(&state->renderer, &state->transientArena, world->camera, entity, V2(0, 0), 0, collideColor, 0, flags); } for (i32 i = 0; i < world->numAudioRenderers; i++) { AudioRenderer *audioRenderer = &world->audioRenderer[i]; audio_updateAndPlay(&state->transientArena, &state->audioManager, audioRenderer); } }