Sign in to follow this  
Mybowlcut

Animating character walking & timing

Recommended Posts

Mybowlcut    176
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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this