예제 #1
0
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));
        }
    }
}
예제 #2
0
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();
            }
        }
}
예제 #3
0
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;
}
예제 #4
0
파일: player.c 프로젝트: Uint1024/CZombie
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);
}
예제 #5
0
/**
 * 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);
    }
}
예제 #6
0
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);
      }
   }
}
예제 #7
0
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 ) );
            }
        }
    }
}
예제 #8
0
파일: Asteroid.c 프로젝트: Doy-lee/Dengine
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);
	}
}
예제 #9
0
파일: bullet.c 프로젝트: Uint1024/CZombie
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);
				}
			}
		}
	}
}
예제 #11
0
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);
			}
		}
	}
}
예제 #12
0
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;
}
예제 #13
0
파일: AI.cpp 프로젝트: Chlorpromazine/game
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;

}