[SDL] help. Smooth movement instead of jumping?

Im coding a RPG atm and im at the part where im making character movement. The code for it is like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void Character::Move(int Direction)
{
	switch (Direction)
	{
	case 0:
		if((CurY + 32)<SCREENHEIGHT) 
		{	
			CurY += 32;
		}
		break;
	case 1:
		if((CurX + 32)<SCREENWIDTH)
		{
			CurX += 32;
		}
		break;
	case 2:
		if((CurY - 32)>0) 
		{
			CurY -= 32;	
		}
		break;
	case 3:
		if((CurX - 32)>0) 
		{
			CurX -= 32;
		}
		break;
	}
}


this function was called in a loop (while the key is pressed). What this code do at the moment is literally making character move 32 pixel while the arrow key is pressed down. This isnt what I want tho, I want it to move slowly 1 by 1 pixel until it reach 32 tile. But i have no idea how to do that

Please excuse my english im not a native english speaker
What this code do at the moment is literally making character move 32 pixel while the arrow key is pressed down.


That makes sense, because that's what you're telling it to do.

To make it move gradually you need to do something like..

move 1 pixel
draw a frame
move 1 pixel
draw a frame
...
etc

But you don't want to put all that logic in one function, because otherwise you don't be updating anything else. Instead you could have some kind of 'target' value, and move towards it.

Something like this (note just a simplistic example... there are many many ways to do this. I wouldn't consider this the best one, but it's simple and it'll give you the general idea):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void Character::Update()  // note:  update is called every logic step, not just
{   // when you want the character to move a tile.
    // so basically... this is called every frame

         if(TargetX < CurX)  --CurX;
    else if(TargetX > CurX) ++CurX;
         if(TargetY < CurY)  --CurY;
    else if(TargetY > CurY)  ++CurY;
}

// Then... if you want to forbid movement "mid-tile":

if( (TargetX == CurX) && (TargetY == CurY) )
{
  // .. allow movement
}
else
{
  // disallow movement, player is still moving between two tiles
}


// ... To move the character a tile you would simply set a target

// to move 'up'
TargetX = CurX;
TargetY = CurY - 32;

EDIT: Disch posted a much more concise answer while I was writing a proper code sample and editing my post.



Last edited on
Just to clarify: You do not want to put this in a singular move function.

Simply adding 1 to the coordinate each time will not create the desired effect. There needs to be a screen draw after each increment -- and you do not want to have any screen draws in a move function because it will interfere with the rest of your game logic.

A simple typical game loop works something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
while( game_is_running )
{
  poll_for_events(); // let the OS know we're still running, catch any interesting events, etc
  
  update_all_objects();  // like moving the player, updating animations, etc

  draw_the_entire_scene();

  wait_for_next_frame();  // don't want to run at fullspeed because it will create
    // a different experience for people on fast computers vs. slow computers.  So
    // check the time and make sure you stay around a certain framerate.  60 FPS is
    // typical.
}



This draw_the_entire_scene() function is the only time you should be doing any drawing to the screen. You do not want to call that function from anywhere else. This means that anything that animates will need to keep track of its state between function calls, like my previous "target" example.
you may want to take a look at behavior tree, a technique used in game AI, it can handle complex game logic like move,attack,...
there's a c++ implementation libbehavior:
https://code.google.com/p/libbehavior/
checkout its example(exe and src)
So, after some coding i ended up with this:

This is code for character updating:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
void Character::Update()
{
	if (isMoving == true)
	{
	if(TargetX < CurX)
	{
		--CurX;
		if((CurX - TargetX > 11) && (CurX - TargetX < 22) )
		{
			if (LeftAlready != false)
			{
				CurDirection = 11;
				LeftAlready = false;
			}
			else
			{
				CurDirection = 10;
				LeftAlready = true;
			}
		}
		else
		{
			CurDirection = 3;
		}
	}
    else if(TargetX > CurX)
	{ 
		++CurX;
		if((TargetX - CurX > 11) && (TargetX - CurX < 22) )
		{
			if (LeftAlready != false)
			{
				CurDirection = 7;
				LeftAlready = false;
			}
			else
			{
				CurDirection = 6;
				LeftAlready = true;
			}
		}
		else
		{
			CurDirection = 1;
		}
	}
    if(TargetY < CurY)
	{ 
		--CurY;
		if((CurY - TargetY > 11) && (CurY - TargetY < 22) )
		{
			if (LeftAlready != false)
			{
				CurDirection = 9;
				LeftAlready = false;
			}
			else
			{
				CurDirection = 8;
				LeftAlready = true;
			}
		}
		else
		{
			CurDirection = 2;
		}
	}
    else if(TargetY > CurY)
	{  
		++CurY;
		if((CurY - TargetY > 11) && (CurY - TargetY < 22) )
		{
			if (LeftAlready != false)
			{
				CurDirection = 5;
				LeftAlready = false;
			}
			else
			{
				CurDirection = 4;
				LeftAlready = true;
			}
		}
		else
		{
			CurDirection = 0;
		}
	}

	if ((CurX == TargetX) && (CurY == TargetY))
	{
		isMoving = false;
		TargetX = TargetY = 0;
	}
	UpdateClip();
	}
}


this is updateclip function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void Character::UpdateClip()
{
	switch (CurDirection)
	{
	case 0:
		box.x = 32;
		box.y = 0;
		break;
	case 1:
		box.x = 32;
		box.y = 32;
		break;
	case 2:
		box.x = 32;
		box.y = 64;
		break;
	case 3:
		box.x = 32;
		box.y = 96;
		break;
	case 4: //Moving down left
		box.x = 0;
		box.y = 0;
		break;
	case 5: //Moving down right
		box.x = 64;
		box.y = 0;
		break;
	case 6: //Moving right left
		box.x = 0;
		box.y = 32;
		break;
	case 7: //Moving right right
		box.x = 64;
		box.y = 32;
		break;
	case 8: //Moving up left
		box.x = 0;
		box.y = 64;
		break;
	case 9: //Moving up right
		box.x = 64;
		box.y = 64;
		break;
	case 10: //Moving left left
		box.x = 0;
		box.y = 96;
		break;
	case 11: //moving left right
		box.x = 64;
		box.y = 96;
		break;
	}
}


and of course the modified move function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void Character::Move(int Direction)
{
	switch (Direction)
	{
	case 0:
		if((CurY + 32)<SCREENHEIGHT) 
		{	
			TargetY = CurY + 32;
			TargetX = CurX;
			isMoving = true;
		}
		break;
	case 1:
		if((CurX + 32)<SCREENWIDTH)
		{
			TargetX = CurX + 32;
			TargetY = CurY;
			isMoving = true;
		}
		break;
	case 2:
		if((CurY - 32)>0) 
		{
			TargetY = CurY - 32;
			TargetX = CurX;
			isMoving = true;
		}
		break;
	case 3:
		if((CurX - 32)>0) 
		{
			TargetY = CurY;
			TargetX = CurX - 32;
			isMoving = true;
		}
		break;
	}
}


the code modified and work correctly, but, there is something i added that was buggy and doesnt turn out right.

THe character sprite doesnt move the way i want it to move.

THis is the sprite im using:

http://www.freemmorpgmaker.com/files/imagehost/pics/25a243219f3d99642a483c74b13998c0.png

So basically the LeftAlready boolean is there to decide whether the charcater have walked with his/her left leg or not. If he/she havent then she/he will be clipped to her walking with left leg sprite. But some how this isnt working right and her walking down sprite doesnt show at all. Can you please check what's wrong?

Thank you
But some how this isnt working right and her walking down sprite doesnt show at all.


The walking down sprite looks to be because you have CurY and TargetY mixed up on line 70.
Topic archived. No new replies allowed.