Dungeon Crawler Challenge - Tile Movement!

posted in JWColeman for project Gogger
Published December 25, 2018
Advertisement

Hello all, since the Frogger Challenge I have been hard at work doing some cleanup in my "engine" and adding a few features that were missing from the first challenge. Specifically, I was able to add add in a state machine as well as figured out how to use SFML for poller based input. I decided that I didn't have enough of one type of art to fully flesh out the graphics of a dungeon crawler, they were all a bit mismatched and I decided to forego frankensteining it together, so I went over to Oryx Design Labs and got their Ultimate Fantasy Tileset!

One of my first major hurdles was that I decided I wanted to use tile based movement rather than the free movement that I used in the Frogger Challenge. I'm trying to slightly mimic the kind of motion i see in Sproggiwood and Paper Dungeons Crawler. I visited the forums for a while and ended up coming up with my own flavor of tile based movement that I believe at least is a close match to what I'm seeing in these games. I wanted diagonal movement, but I wanted everything locked to the tiles. and I think I have accomplished that at this time! See Below:

2018-12-24_00-10-03.mp4

This was more of a task than I thought it would be, but here is the code that makes it work, I'm definitely open to some suggestions here!

 

Firstly, input!


if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) && sf::Keyboard::isKeyPressed(sf::Keyboard::D))
	{
		if(gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->setVelocity(XMFLOAT3{ float(.025) * dt,float(.025) * dt, 0 });
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x + 1;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y + 1;
		}

	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) && sf::Keyboard::isKeyPressed(sf::Keyboard::A))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->setVelocity(XMFLOAT3{ float(-.025) * dt,float(.025) * dt, 0 });
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x - 1;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y + 1;
		}
	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) && sf::Keyboard::isKeyPressed(sf::Keyboard::D))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->setVelocity(XMFLOAT3{ float(.025) * dt,float(-.025) * dt, 0 });
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x + 1;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y - 1;
		}
	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) && sf::Keyboard::isKeyPressed(sf::Keyboard::A))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->setVelocity(XMFLOAT3{ float(-.025) * dt,float(-.025) * dt, 0 });
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x - 1;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y - 1;
		}
	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->getPhysics()->SetVelocityX(float(.025) * dt);
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x + 1;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y;
		}

	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->getPhysics()->SetVelocityX(float(-.025) * dt);
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x - 1;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y;
		}
	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->getPhysics()->SetVelocityY(float(.025) * dt);
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y + 1;
		}
	}
	else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
	{
		if (gameobjects[0]->getPhysics()->inMotion == false)
		{
			gameobjects[0]->getPhysics()->SetVelocityY(float(-.025) * dt);
			gameobjects[0]->nextmapcoords.x = gameobjects[0]->mapcoords.x;
			gameobjects[0]->nextmapcoords.y = gameobjects[0]->mapcoords.y - 1;
		}
	}

So, I had to add some information to my gameobject class. Specifically, map coordinates, and next map coordinates. Then I had to limit my input to only when inmotion is false, which will be false whenever I have successfully locked to a tile. Now, to make all the map coordinates work correctly, I needed to be able to update the next map coordinates and current map coordinates in my game object update loop, using this code:


void Game::UpdateMapPosition(GameObject * object)
{
	XMFLOAT3A objectpos = object->getPosition();

	int xcount = floor(objectpos.x / map->tileSizeX);
	int ycount = floor(objectpos.y / map->tileSizeY);

	object->mapcoords.x = xcount;
	object->mapcoords.y = ycount;

	XMFLOAT3A pos = map->At(xcount, ycount);
	if (object->currentDirection == Facing::UP_RIGHT || object->currentDirection == Facing::DOWN_LEFT)
	{
		if (pos.x == map->At(object->nextmapcoords.x, object->nextmapcoords.y).x)
		{
			object->getPhysics()->SetVelocityX(0);
		}
		else if (pos.y == map->At(object->nextmapcoords.x, object->nextmapcoords.y).y)
		{
			object->getPhysics()->SetVelocityY(0);
		}

	}
	else if (object->currentDirection == Facing::UP_LEFT || object->currentDirection == Facing::DOWN_RIGHT)
	{
		if (pos.x == map->At(object->nextmapcoords.x, object->nextmapcoords.y).x)
		{
			object->getPhysics()->SetVelocityX(0);
		}
		else if (pos.y == map->At(object->nextmapcoords.x, object->nextmapcoords.y).y)
		{
			object->getPhysics()->SetVelocityY(0);
		}

	}
	else if(object->currentDirection == Facing::RIGHT || object->currentDirection == Facing::LEFT)
	{
		if (pos.x == map->At(object->nextmapcoords.x, object->nextmapcoords.y).x)
		{
			object->getPhysics()->SetVelocityX(0);
		}
		else if (pos.y == map->At(object->nextmapcoords.x, object->nextmapcoords.y).y)
		{
			object->getPhysics()->SetVelocityY(0);
		}

	}
	else if(object->currentDirection == Facing::UP || object->currentDirection == Facing::DOWN)
	{
		if (pos.y == map->At(object->nextmapcoords.x, object->nextmapcoords.y).y)
		{
			object->getPhysics()->SetVelocityY(0);
		}
		else if (pos.y == map->At(object->nextmapcoords.x, object->nextmapcoords.y).y)
		{
			object->getPhysics()->SetVelocityY(0);
		}
	}
}

Again, definitely open to suggestions for cleanup here, this is what I was able to throw together given my current knowledge and understanding. The end result is definitely functional though! The next thing I think I want to do is incorporate the mouse in some kind of way, but I haven't thought up any ideas yet, lets here what you think! There are a few things I like about this setup, and of course a few that I don't like. I think the code is pretty easy to read, and I like that. However, It feels a bit bloated and large for the job its actually accomplishing, definitely some room for some tidying up and optimization.

 

Anyways I think I've made a good start for the next challenge. What's next? Maybe make some of my objects interactable, like boxes and crates and junk. Loot is, I believe, the biggest part of the requirement, aside from beating the bad guys!

4 likes 0 comments

Comments

JWColeman

Lol, I should really examine my code before i post it. So many redundant if else statements!

December 25, 2018 09:40 PM
Rutin

Keep up the great work! I'm looking forward to seeing how this develops! :D 

December 25, 2018 09:53 PM
Septopus

Looks excellent to me(the movement) I'm no help with this c though.. ;)

December 26, 2018 01:09 AM
JWColeman

I'm beginning to think that I need to rework this so that I'm not using a physics class in order to accomplish this task. I took a bit of a broad stance on what physics was when i first started developing this thing. Essentially, I said to myself, if it moves, its physics. But it may be that I've overcomplicated my code following this rule, not sure.

Like, currently, I'm using AABB collision in a map/tile/grid environment. and I'm not sure if that makes sense. I could just simply say, is the map tile you want to move to walkable? yes/no, do logic. But instead, I'm going through the steps to detect a collision and respond appropriately. This is what my physics class is currently doing. 

Also, all positions for game objects are derived from physics. If I tell a game object to move, its updating the physical component, which then in turn updates the user (the game object). This might be a level of complexity I can do without.

December 27, 2018 04:55 PM
Septopus
35 minutes ago, JWColeman said:

This might be a level of complexity I can do without.

When ever I seriously ask myself that question, I almost always answer it positively.  I've actually grown quite fond of ripping out unnecessary code piles, kinda like weeding a garden.  Almost therapeutic.. ;)

December 27, 2018 05:36 PM
JWColeman
1 hour ago, Septopus said:

When ever I seriously ask myself that question, I almost always answer it positively.  I've actually grown quite fond of ripping out unnecessary code piles, kinda like weeding a garden.  Almost therapeutic.. ;)

The thing about this code, is that I know I will eventually use it again, it just doesn't have much of a place in a tile based environment. I would have to configure my core objects to operate with or without it. Currently my game object relies on a position derived from it's physical component. So I would have to make that like, optional. Somehow :D. Refactoring sucks when there is a known deadline :).

December 27, 2018 06:45 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement