Jump to content
  • Advertisement
Sign in to follow this  
Mybowlcut

Animating character walking & timing

This topic is 3474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey. I'm trying to animate a character walking. When you press an arrow key, the player moves in that direction, with a stop in between the tiles to show that they are walking (left leg/arm or right leg/arm forward - alternates). It works, but I don't like how I've designed it... Also, the stop in between the tiles is based on the game timer which I'm not sure about... it seems to me to be a bad way to do it... so I'll post the code and see what you guys think. Player_View:
void Player_View::Render_View(SDL_Renderer& renderer, const Player& player,
const SDL_Rect& camera, const Point& camera_offset)
{
	const SDL_Surface* surface = renderer.Surface_At(player.Image_Fn());
	SDL_Rect clip = SDL_Tools::calculate_clip(surface->w, surface->h,
		player.Frame(), player.Facing());
	
	renderer.Render(SDL_Renderer::D2, camera_offset + player.Position() -
		SDL_Tools::to_point_xy(camera),	player.Image_Fn(), clip);
}

Player_Controller:
void Player_Controller::Update(Player& player, unsigned int time)
{
	using namespace Direction;
	if(player.Walking())
	{
		if(+(time - last_time_moved) > movement_delay)
		{ // Sufficient time elapsed; ok to finish move.
			player.Move(player.Facing(), axis_from_direction(player.Facing()) == X_AXIS
				? Tile::TILE_WIDTH / 2 : Tile::TILE_HEIGHT / 2);
			last_time_moved = 0;
		}
	}
}

void Player_Controller::Do_Logic(Player& player,
const Level& current_level, const SDL_Event* event_, unsigned int time)
{
	if(player.Walking()) return; // Must wait for walk to finish.

	using namespace Direction;
	using namespace SDL_Tools;

	DIRECTION attempted_dir = get_direction_from_sym(event_->key.keysym);
	if(attempted_dir == NO_DIRECTION) return;

	player.Face(attempted_dir);

	if(event_->key.state == SDL_PRESSED)
	{ // Tried to move.
		Point attempted_pos = move_by(player.Position(), attempted_dir, 32);
		if(current_level.Can_Walk(attempted_pos))
		{ // Can move to attempted position; move.
			player.Move(attempted_dir, axis_from_direction(player.Facing()) == X_AXIS
				? Tile::TILE_WIDTH / 2 : Tile::TILE_HEIGHT / 2);
			last_time_moved = time;
		}
	}
}

Character:
void Character::Move(Direction::DIRECTION direction, unsigned short distance)
{
	using namespace Frame;

	walking = !walking; // Toggle if between two tiles or not.

	if(!walking) frame = OVER;
	// Alternate between left leg/foot and right leg/foot forward.
	else walk(frame, last_walking_frame);
	
	position = SDL_Tools::move_by(position, direction, distance);
	facing = direction;
}

This is my driver program that just tests the code:
void Test_Game::Run()
{
	timer.Start();

	Point inv_rp(renderer.Screen_Width() - 200, renderer.Screen_Height() - 200);
	Point inv_sl(3, 3);

	while(!exit)
	{
		while(SDL_PollEvent(&sdl_event))
		{
			if(sdl_event.type == SDL_QUIT || sdl_event.key.keysym.sym == SDLK_ESCAPE)
			{
				exit = true;
				break;
			}
			else if(sdl_event.type == SDL_MOUSEMOTION)
			{
				continue;
			}

			// Update player based on time.
			player_controller.Update(player, timer.Get_Ticks());
			// Handle any events.
			player_controller.Do_Logic(player, level_manager.Current_Level(),
				&sdl_event, timer.Get_Ticks());
			// Render player.
			player_view.Render_View(renderer, player,
				level_manager.Camera().Camera(), level_manager.Camera().Offset());
			// Render player's inventory.
			player_inventory_view.Render_View(
				renderer, player.inventory, inv_rp, inv_sl);

			level_manager.Do_Logic(&sdl_event, player);
			level_manager.Render_View(renderer);
		}

		// Update player based on time.
		player_controller.Update(player, timer.Get_Ticks());
		// Render player.
		player_view.Render_View(renderer, player,
			level_manager.Camera().Camera(), level_manager.Camera().Offset());
		// Render player's inventory.
			player_inventory_view.Render_View(
				renderer, player.inventory, inv_rp, inv_sl);
		
		level_manager.Do_Logic(&sdl_event, player);
		level_manager.Render_View(renderer);

		if(timer.Get_Ticks() >= 1000)
		{
			timer.Start();
		}

		Render_Debug_Info();
		
		renderer.Draw_Screen();
	}
}

I'm certain there is a better way to do this.. any ideas? Cheers.

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!