static void updateEntities(PlayState *playState, EntityNode **entities, GameContext *gameContext, UserInput *userInput, GameMemory *gameMemory) { for (EntityNode **entityNode = entities; *entityNode;) { V2D position = getEntityScreenPosition(&(*entityNode)->entity, gameContext->cameraPosition); if (((*entityNode)->entity.type == PLAYER_BULLET_TYPE || (*entityNode)->entity.type == ENEMY_BULLET_TYPE || (*entityNode)->entity.type == NULL_ENTITY_TYPE) && (position.x < -(*entityNode)->entity.bitmap.width || position.x > gameContext->gameWidth + (*entityNode)->entity.bitmap.width || position.y < -(*entityNode)->entity.bitmap.height || position.y > gameContext->gameHeight + (*entityNode)->entity.bitmap.height || (*entityNode)->entity.dyingCounter == 1)) { (*entityNode)->entity.dyingCounter = 0; EntityNode *freeEntity = *entityNode; // NOTE: must modify the pointer itself *entityNode = (*entityNode)->next; freeEntity->next = playState->freeEntities; playState->freeEntities = freeEntity; assert((*entityNode == 0) || (*entityNode != (*entityNode)->next)); } else { updateEntity(playState, &(*entityNode)->entity, gameContext, userInput, gameMemory); moveEntity(playState, &(*entityNode)->entity, gameContext, userInput); entityNode = &(*entityNode)->next; assert((*entityNode == 0) || (*entityNode != (*entityNode)->next)); } } }
void EntityRainFX::onUpdate() { prevPosX = posX; prevPosY = posY; prevPosZ = posZ; motionY -= particleGravity; moveEntity(motionX, motionY, motionZ); motionX *= 0.98000001907348633; motionY *= 0.98000001907348633; motionZ *= 0.98000001907348633; if(particleMaxAge-- <= 0) { setEntityDead(); } if(onGround) { if(Math.random() < 0.5) { setEntityDead(); } motionX *= 0.69999998807907104; motionZ *= 0.69999998807907104; } Material material = worldObj.getBlockMaterial(MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)); if(material.getIsLiquid() || material.isSolid()) { double d = (float)(MathHelper.floor_double(posY) + 1) - BlockFluid.getPercentAir(worldObj.getBlockMetadata(MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ))); if(posY < d) { setEntityDead(); } } }
static int luaMoveEntity(lua_State *L){ pent e = lua_touserdata(L, 1); position x = luaL_checknumber(L, 1); position y = luaL_checknumber(L, 1); moveEntity(e, x, y); lua_pushvalue(L, 1); return 1; }
void Player_Move(Entity* p, float dx, float dy) { moveEntity(p, dx, dy); p->playerC->cameraX += dx; p->playerC->cameraY += dy; Graphics_MoveCamera(dx, dy); }
/** * Envoie une entité tant que sont état n'est pas final. * @param game L'état du jeu * @param hero Le héros * @param entity L'entité à envoyer * @param board Le plateau de jeu */ void throwEntity(GameState* game, Eceman* hero, Entity* entity, char board[ROWS][COLS]) { unsigned int i; i = 0; while (entity->state != FINAL) { i++; if (i % 20000000 != 0) continue; clearEntity(board, entity); moveEntity(game, hero, entity, board); drawEntity(board, entity); } }
void moveForward(ENTITY *entity, GAMESTATE* state, DISPLAY* display) { CELL *destination = NULL; CELL *parent = entity->parent; switch (entity->facing){ case down : destination = parent->below; break; case left : destination = parent->left; break; case up : destination = parent->above; break; case right : destination = parent->right; break; default : entity->facing = up; } if (canMove(destination) == true){ if (destination->type == WATER) decreaseHealth(state, NEGHEALTH); moveEntity(destination, parent); } else if (canMove(destination) == false){ if (destination != NULL){ doActionIfNotEmpty(display, state, destination->entity); } } }
void World::update( float dt ) { //Update the population, mostly does AI decisions mPop.update( dt ); float mBlockDimensions = 0.3f; //Do collision for moving characters for( int i = 0; i < POPULATION_MAX_CHARACTERS; i++){ Character& character = mPop.getCharacter(i); if( character.getExistence() > Character::Existence::Dead ){ XMFLOAT4& dir = mPop.getCharacter(i).getWalkingDirection(); //Make sure we are at least moving when checking collision float dist = fabs( dir.x ) + fabs( dir.z ); if( dist < 0.1f ){ continue; } //TEMPORARY WAY OF SOLVING THIS! //As long as we are not on a ramp, bring us to the floor int bx = static_cast<int>( character.getPosition().x / mBlockDimensions ); int bz = static_cast<int>( character.getPosition().z / mBlockDimensions ); CLAMP( bx, 0, getLevel().getWidth() - 1 ); CLAMP( bz, 0, getLevel().getDepth() - 1 ); XMVECTOR moveVec = XMLoadFloat4( &dir ); moveVec = XMVector3Normalize( moveVec ); moveVec = XMVectorSetW( moveVec, 1.0f ); moveEntity( &character, moveVec, dt * CHARACTER_MOVE_SPEED ); //Reset the direction back to 0 dir.x = 0.0f; dir.y = 0.0f; dir.z = 0.0f; } } for(ushort i = 0; i < mLevel.getNumDoors(); i++){ Level::Door& door = mLevel.getDoor(i); if( door.state == Level::Door::Opening ){ door.setYRotation( door.getYRotation() + 0.02f ); if( door.getYRotation() > ( door.startAngle + ( 3.14159f * 0.5f ) ) ){ door.state = Level::Door::Opened; door.setYRotation( door.startAngle + ( 3.14159f * 0.5f ) ); } }else if( door.state == Level::Door::Closing ){ door.setYRotation( door.getYRotation() - 0.02f ); if( door.getYRotation() < ( door.startAngle - ( 3.14159f * 0.5f ) ) ){ door.state = Level::Door::Closed; door.setYRotation( door.startAngle - ( 3.14159f * 0.5f ) ); } } } }
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); } }
void Bullet_Update(Entity* bullet, World* world) { bullet->alive_timer -= delta_g; if(bullet->alive_timer <= 0) { bullet->alive = false; } if(bullet->alive) { moveEntity(bullet, bullet->movementC->dx * delta_g, bullet->movementC->dy * delta_g); if(!bullet->is_ennemy) { for(int i = 0 ; i < Vector_Count(&world->monsters_vector) ; i++) { Entity* mob = (struct Entity*)Vector_Get(&world->monsters_vector, i); if (BoundingBox_CheckSimpleCollision(&bullet->box, &mob->box) && mob != bullet->last_zombie_hit) { bullet->last_zombie_hit = mob; Zombie_GetAttacked(mob, bullet->damage, world); int random = rand() % 1000; //modulo the address by 1000 to get a kinda random number if(bullet->nb_penetrations < 4 && random < bullet->penetration_chance) { bullet->nb_penetrations++; } else { bullet->alive = false; } } } } else { //wow I really need to improve this mess //put the collision detection on the zombie's side //and pass the attack direction to the player Box* temp = BoundingBox_CreateTemp(bullet); Direction bullet_coming_from = BoundingBox_CheckCollision(&bullet->box, temp, &world->player.box); if(bullet_coming_from != None && world->player.playerC->invulnerability_timer <= 0) { Entity* collision_direction[5] = {NULL}; collision_direction[bullet_coming_from] = bullet; Player_TakeDamage(&world->player, collision_direction); bullet->alive = false; } free(temp); } for(int i = 0 ; i < Vector_Count(&world->non_null_walls) && bullet->alive; i++) { Entity* wall = (Entity*)Vector_Get(&world->non_null_walls, i); if( Entity_CheckNear(bullet, wall) && wall->solid && BoundingBox_CheckSimpleCollision(&bullet->box, &wall->box)) { Structure_GetAttacked(wall, bullet); bullet->alive = false; } } } }
void Pacman::onTick() { // Cambiar dirección deseada de Pacman if(m_input->getKeyPress()->Up.value) { m_player.DesiredDirection = ViewDirection::Up; } else if(m_input->getKeyPress()->Right.value) { m_player.DesiredDirection = ViewDirection::Right; } else if(m_input->getKeyPress()->Left.value) { m_player.DesiredDirection = ViewDirection::Left; } else if(m_input->getKeyPress()->Down.value) { m_player.DesiredDirection = ViewDirection::Down; } if(m_readyTimer.getTicks() > 0) { if(m_readyTimer.getTicks() >= 2000) { m_readyTimer.stop(); m_gameTimer.start(); m_frameTimer.start(); } return; } if(m_pauseTimer.getTicks() > 0) { if(m_pauseTimer.getTicks() >= 500) { m_pauseTimer.stop(); m_gameTimer.resume(); m_frameTimer.resume(); if(m_ghostKillTimer.isPaused()) { m_ghostKillTimer.resume(); } if(m_player.IsDead) { resetGame(); } } return; } // Animar Pacman y Fantasmas (Cambio de Frames) if(m_frameTimer.getTicks() > 50) { if(m_player.Moving) { m_player.CurrentFrame++; if(m_player.CurrentFrame > 3) { m_player.CurrentFrame = 0; } } else { m_player.CurrentFrame = 1; } for(unsigned int x = 0; x < m_ghostCount; ++x) { m_ghost[x].CurrentFrame++; if(m_ghost[x].CurrentFrame > 1) { m_ghost[x].CurrentFrame = 0; } } m_frameTimer.start(); } // Mover Pacman moveEntity(&m_player.CurrentCellIndex, &m_player.PositionOffset, &m_player.Direction, &m_player.DesiredDirection, &m_player.Moving, m_player.MoveSpeed, true); bool ghostForceRefresh = false; sf::Vector2i findCoin = sf::Vector2i(m_player.CurrentCellIndex % m_mapSize.x, floor(m_player.CurrentCellIndex / m_mapSize.x)); // Comer bolas (Pacman) y actualizar mapa for(unsigned int x = 0; x < m_ballPosition.size(); ++x) { if(m_ballPosition[x] == findCoin) { mapSetCell(m_player.CurrentCellIndex, CellType::Nothing); m_ballPosition.erase(m_ballPosition.begin() + x); addScore(10); m_sound.setBuffer(m_ballSound); m_sound.play(); if(m_ballPosition.empty() && m_ballBigPosition.empty()) { resetGame(); return; } } } for(unsigned int x = 0; x < m_ballBigPosition.size(); ++x) { if(m_ballBigPosition[x] == findCoin) { mapSetCell(m_player.CurrentCellIndex, CellType::Nothing); m_ballBigPosition.erase(m_ballBigPosition.begin() + x); m_powerupKillCounter = 0; m_ghostKillTimer.start(); ghostForceRefresh = true; m_sound.setBuffer(m_powerupSound); m_sound.play(); for(unsigned int x = 0; x < m_ghostCount; ++x) { m_ghost[x].Invulnerable = false; } addScore(50); if(m_ballPosition.empty() && m_ballBigPosition.empty()) { resetGame(); return; } } } if(m_ghostKillTimer.getTicks() > 7000) { m_ghostKillTimer.stop(); for(unsigned int x = 0; x < m_ghostCount; ++x) { m_ghost[x].Invulnerable = false; m_ghost[x].LastStateChange = m_gameTimer.getTicks(); m_ghost[x].StateDuration = 3000; m_ghost[x].IsInChase = true; } ghostForceRefresh = true; } // IA Fantasmas for(unsigned int x = 0; x < m_ghostCount; ++x) { if(m_ghost[x].TimeToRelease >= m_gameTimer.getTicks()) { break; } unsigned int ignoreCell; if(m_ghost[x].Direction == ViewDirection::Left) { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Right); } else if(m_ghost[x].Direction == ViewDirection::Right) { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Left); } else if(m_ghost[x].Direction == ViewDirection::Up) { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Down); } else { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Up); } float ghostMoveSpeed = m_ghostKillTimer.isStarted() && (m_ghost[x].IsDead ? false : !m_ghost[x].Invulnerable) ? (m_ghost[x].MoveSpeed / 2) : (m_ghost[x].IsDead ? m_ghost[x].MoveSpeed * 1.5: m_ghost[x].MoveSpeed); if(m_ghost[x].CurrentCellIndex == m_ghost[x].HomeIndex) { m_ghost[x].IsDead = false; if(m_ghostKillTimer.isStarted()) { m_ghost[x].Invulnerable = true; } m_ghost[x].LastStateChange = m_gameTimer.getTicks(); m_ghost[x].StateDuration = 1000; m_ghost[x].IsInChase = true; } if(m_gameTimer.getTicks() >= (m_ghost[x].LastStateChange + m_ghost[x].StateDuration)) { if(!m_ghostKillTimer.isStarted()) { ghostForceRefresh = true; } m_ghost[x].LastStateChange = m_gameTimer.getTicks(); if(m_ghost[x].IsInChase) { m_ghost[x].IsInChase = false; m_ghost[x].StateDuration = (3000 + (rand() % 3000)); } else { m_ghost[x].IsInChase = true; m_ghost[x].StateDuration = (5000 + (rand() % 3000)); } } if(m_ghost[x].LastCellChecked != m_ghost[x].CurrentCellIndex || ghostForceRefresh) { if(m_ghost[x].IsDead) { m_ghost[x].DesiredDirection = getNextDirection(m_ghost[x].CurrentCellIndex, m_ghost[x].HomeIndex, ignoreCell); } else if(m_ghost[x].IsInChase && (!m_ghostKillTimer.isStarted() || m_ghost[x].Invulnerable)) { if(m_ghost[x].CurrentCellIndex != m_player.CurrentCellIndex) { m_ghost[x].DesiredDirection = getNextDirection(m_ghost[x].CurrentCellIndex, m_player.CurrentCellIndex, ignoreCell); } } else { unsigned int tempIndex; std::vector<unsigned int> possibleCells; if(m_ghost[x].Direction != ViewDirection::Left) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Left); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } if(m_ghost[x].Direction != ViewDirection::Right) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Right); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } if(m_ghost[x].Direction != ViewDirection::Up) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Up); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } if(m_ghost[x].Direction != ViewDirection::Down) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Down); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } // Si hay caminos alternativos a seguir (Que no sea ni a donde se dirige ni la casilla anterior) o es un callejón sin salida... if(possibleCells.size() > 0 || getMapInfo(m_ghost[x].CurrentCellIndex, m_ghost[x].Direction) == CellType::Wall) { m_ghost[x].DesiredDirection = getRandomDirection(m_ghost[x].CurrentCellIndex, ignoreCell); } } m_ghost[x].LastCellChecked = m_ghost[x].CurrentCellIndex; } moveEntity(&m_ghost[x].CurrentCellIndex, &m_ghost[x].PositionOffset, &m_ghost[x].Direction, &m_ghost[x].DesiredDirection, &m_ghost[x].Moving, ghostMoveSpeed, false); if(!m_ghost[x].IsDead) { // Calcular colisión con Pacman if(m_ghost[x].CurrentCellIndex == m_player.CurrentCellIndex) { ghostCollide(x); } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Left) == m_player.CurrentCellIndex) { if((m_player.PositionOffset.x + (m_tileSize.x / 2)) - (m_ghost[x].PositionOffset.x + (m_tileSize.x / 2)) >= 0) { ghostCollide(x); } } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Right) == m_player.CurrentCellIndex) { if((m_ghost[x].PositionOffset.x + (m_tileSize.x / 2)) - (m_player.PositionOffset.x + (m_tileSize.x / 2)) >= 0) { ghostCollide(x); } } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Up) == m_player.CurrentCellIndex) { if((m_player.PositionOffset.y + (m_tileSize.y / 2)) - (m_ghost[x].PositionOffset.y + (m_tileSize.y / 2)) >= 0) { ghostCollide(x); } } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Down) == m_player.CurrentCellIndex) { if((m_ghost[x].PositionOffset.y + (m_tileSize.y / 2)) - (m_player.PositionOffset.y + (m_tileSize.y / 2)) >= 0) { ghostCollide(x); } } } } }
void doEnemies() { bool helpless; float fallSpeed; for (Unit *unit = (Unit*)entityManager->enemyList.getFirstElement() ; unit != NULL ; unit = (Unit*)unit->next) { self = unit; //self->riding = NULL; bbManager->removeBox(unit); // final battle... if (unit->contentType & CONTENTS_PLAYERCLIP) { unit->health = 0; unit->flags |= EF_DEAD; } if (unit->health <= 0) { if (unit->flags & EF_DEAD) { if (!unit->referenced) { if (player->target == unit) { player->target = NULL; } unit = (Unit*)unit->previous; entityManager->enemyList.remove(unit->next); if (entityManager->enemyList.getSize() == 0) { fireTriggers("ANY_ENEMY", TRIGGER_TYPE_ALL_ENEMIES_KILLED); } continue; } else { unit->referenced = false; } continue; } else if (!(unit->flags & EF_DYING)) { unit->die(); if (!unit->dead) { fireTriggers(unit->getName(), TRIGGER_TYPE_ENTITY_KILLED); fireTriggers("ANY_ENEMY", TRIGGER_TYPE_ENTITY_KILLED); unit->dead = true; } unit->flags |= EF_DYING; if (!(unit->flags & EF_STATIC)) { unit->flags |= EF_BOUNCES; } addBloodParticle(unit->position.x, unit->position.y, unit->position.z); if (unit->contentType & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) { debug(("%s drowned...\n", unit->getName())); } } } if ((unit->spawnedIn) && (unit->lastPlayerSighting >= 6000) && (!unit->referenced)) { addTeleportParticles(unit->position); unit = (Unit*)unit->previous; entityManager->enemyList.remove(unit->next); continue; } if (unit->target != NULL) { unit->target->referenced = true; } if (unit->owner != NULL) { unit->owner->referenced = true; } unit->referenced = false; helpless = (unit->helpless > 0); if ((!game->allStatic) && (game->cutsceneType != CUTSCENE_INGAME)) { if ((!helpless) || (unit->health < 1)) { if (unit->performNextAction(engine->getTimeDifference(TD_LOGIC))) { if (unit->action != NULL) { unit->action(); } } } } if (game->cutsceneType != CUTSCENE_INGAME) { unit->think(engine->getTimeDifference(TD_LOGIC)); } if (unit->flags & (EF_TELEPORTING|EF_VANISHED)) { continue; } if (withinViewableRange(unit)) { entityManager->addEntityToDrawList(unit); if (unit->flags & EF_WEIGHTLESS) { addGravUnitParticles(unit, GLColor::purple, GLColor::blue); } } if ((unit->liquidLevel > 1) && (!(unit->flags & EF_SWIMS))) { if ((unit->definition->type == NME_DARK_BLOB) && (unit->health > 0)) { generalUnitVanish(player->position, Math::rrand(300, 400)); continue; } else if (unit->health > 0) { unit->applyDamage(RAND_MAX, DAMAGE_SPECIAL); } } // was helpless but now isn't - Stop sliding! if ((helpless) && (unit->helpless <= 0)) { if ((unit->flags & EF_ONGROUND) || (!(unit->contentType & CONTENTS_SOLID)) || (unit->flags & EF_WEIGHTLESS)) { unit->totalCurrentDamage = 0; unit->rotation.set(0, 0, 0); unit->flags &= ~EF_BOUNCES; } else { unit->helpless = 1; } } unit->applyGravity(engine->getTimeDifference(TD_LOGIC)); keepUnitAwayFromEdges(unit); fallSpeed = unit->realVelocity.z; if (fallSpeed <= FALL_DAMAGE_ACCEL) { unit->helpless = 5; unit->flags |= EF_BOUNCES; } // don't let swimming blobs move too quickly if ((unit->flags & EF_SWIMS) && (unit->liquidLevel == 2)) { Math::limit(&unit->velocity.x, -0.1, 0.1); Math::limit(&unit->velocity.y, -0.1, 0.1); Math::limit(&unit->velocity.z, -0.1, 0.1); } moveEntity(unit); if ((fallSpeed <= FALL_DAMAGE_ACCEL) && (unit->velocity.z > FALL_DAMAGE_ACCEL) && (unit->contentType & CONTENTS_SOLID)) { unit->velocity.z = 1.0; fallSpeed = fabs(fallSpeed * 1.5); if (!(unit->flags & EF_DYING)) { unit->applyDamage(fallSpeed, DAMAGE_SPECIAL); unit->shield = -2.5; audio->playSound(SND_HIT, CH_ANY, camera->getSoundDistance(unit->position)); debug(("%s took %.2f damage from fall [%s]\n", unit->getName(), fallSpeed, unit->position.toString())); } else { unit->health = -100; unit->flags |= EF_DYING; } } if ((unit->position.z < bsp->minCords.z) && (unit->health > 0)) { printf("WARNING: Enemy '%s' fell out of map at %s\n", unit->getName(), unit->position.toString()); printf("Map Mins: %s\n", bsp->minCords.toString()); printf("Map Maxs: %s\n", bsp->maxCords.toString()); printf("On Ground = %ld\n", (unit->flags & EF_ONGROUND)); printf("Velocity = %s\n", unit->velocity.toString()); unit->health = -100; unit->flags |= EF_DEAD; continue; #if DEV exit(1); #endif } if (unit->flags & EF_ONFIRE) { addOnFireParticles(); } bbManager->addBox(unit); if ((unit->definition->type == NME_DARK_BLOB) && (unit->health > 0)) { Math::limit(&unit->helpless, 0, 25); } if ((unit->flags & EF_ALWAYS_FACE) && (unit->health > 0)) { if ((!unit->helpless) && (unit->target != NULL)) { faceTarget(unit); } } } }
frts::Job::State frts::HarvestJob::execute(const SharedManagerPtr& shared) { assert(shared != nullptr); assert(this->jobState != JobState::Finished); State result = State::Running; auto uaf = getUtility<UserActionFactory>(shared, UserActionIds::userActionFactory()); if (jobState == JobState::FirstExecution) { jobState = JobState::Goto; // Calculate path. auto rm = getDataValue<RegionManager>(shared, ModelIds::regionManager()); auto pos = rm->getPos(toHarvest, shared); // Already harvested? if (pos == nullptr) { result = State::Stop; } else { // Find a path to one of the neighbors of the job position. bool pathFound = uaf->findPathToJob(getExecutingEntity(), pos, true, shared); if (!pathFound) { result = State::Cancel; } } // Not necessary to change due time. Start at the next frame. } else if (jobState == JobState::Goto) { // Already harvested? if (!isValid(shared)) { result = State::Stop; } auto moveResult = uaf->moveEntity(getExecutingEntity(), shared); if (moveResult.state == UserActionFactory::MoveEntityState::Moved) { // Set next due time. setDueTime(shared->getFrame()->getRunTime() + moveResult.nextMoveTime); } else if (moveResult.state == UserActionFactory::MoveEntityState::AtTarget) { jobState = JobState::Harvest; // Set next due time. auto harvestable = getComponent<Harvestable>(shared->makeId(ComponentIds::harvestable()), toHarvest); auto harvestTime = fromMilliseconds(round<unsigned int>(1000.0 / harvestable->getSpeed())); setDueTime(shared->getFrame()->getRunTime() + harvestTime); } else { // Try again. jobState = JobState::FirstExecution; } } else if (jobState == JobState::Harvest) { jobState = JobState::Finished; result = State::Finished; // Remove toHarvest entity. auto rm = getDataValue<RegionManager>(shared, ModelIds::regionManager()); auto pos = rm->removeEntity(toHarvest, shared); // Already harvested? if (pos == nullptr) { result = State::Stop; } else { // Drops. uaf->createDrops(toHarvest, pos, shared); } // Remove marker and set to null. clearJobMarker(shared); // Check if other jobs at this position are still valid. if (pos != nullptr) { uaf->confirmJobsValidOrStop(pos, shared); } } // Job was previously stopped but the job manager doesn't know yet. else if (jobState == JobState::Stopped) { result = State::Stop; } return result; }
void AI::movementFromPath(int entityNumber) { try //if entity is not created { currentPaths.at(entityNumber); } catch (const out_of_range& oor) { cout << "Error, entity number not found for path" << endl; system("pause"); exit(0); } if (currentPaths[entityNumber].fullPath.size() < 1) //don't do anything if there's no current movement for the entity return; string path = currentPaths[entityNumber].fullPath; //take the first direction from the path and move there switch (path[0]) { case '0': moveEntity(-1, 0); break; case '1': moveEntity(-1, -1); break; case '2': moveEntity(0, -1); break; case '3': moveEntity(1, -1); break; case '4': moveEntity(1, 0); break; case '5': moveEntity(1, 1); break; case '6': moveEntity(0, 1); break; case '7': moveEntity(-1, 1); break; default: cout << "error: invalid movement" << endl; break; } float distMax = 0; //distance from next tile int dist; //distance from next pixel if ((int)path[0] % 2 == 0) //if pair, distance is 15-1 pixel (-1 so start-end doesn't use same pixel), straight line { distMax = 14; dist = 1; } else //odd, distance is 28 (14*2), diagonally { distMax = 28; dist = 2; } if (currentPaths[entityNumber].timeNext > distMax)//arrived at next tile { currentPaths[entityNumber].fullPath.erase(0, 1); currentPaths[entityNumber].timeNext = 0; } else currentPaths[entityNumber].timeNext += dist; }