Main Menu

Sprite pathing and control

Started by LemonWizard, June 24, 2010, 05:09:46 PM

Previous topic - Next topic

LemonWizard



Okay, after careful debate I decided I would share with the community because I think I am at the point where input is helpful.

I was fiddling around in pb one evening, late. I was trying to create a drawing app that was small and simple to use that had a rewind feature. To compliment my recent experiments in modding super mario world and using snes9x videos and playback to break the game or test for rom bugs.

Needless to say, it worked. I was trying to go for something like a frame by frame ram dump, so that values would basically be saved into an instance variable which had a lifespan of one frame when played back.
The game engine itself would just run the values through, and behave accordingly. Interesting concept which I'm still working on is giving my programs their own memory of the last few frames. For debugging purposes. Then, I thought to store a specific set of values in a long term array, which could then be played back through the engine frame by frame.

Eventually, all of this effort combined led me to create a path array for sprites. And what I found was a solution to a problem I've had with sprites for a while. How do I make them dynamically move? You see, I hadn't previously figured out how to make paths for sprites before this. I was trying to use a list of coordinates manually typed out and I hadn't thought to record them into an array using the mouse. Except.. the result for now is still a little unsatisfying since I can't yet make the paths span a larger screen. (One that is split up into a large 2d world)

The mainstay goal here, is to handle sprite pathing with either 2 methods.

1-A value between 1 and 8, to allow for angled movement. Up, down left right, Upleft, Upright, downleft, downright.

2-A value which is coordinate specific, in the next step.
This works sort of fine... but not quite. Since if I want intelligently behaving sprites AI has to be incorperated somehow.. so basically. I have to use different movement modes..

The solution I'm trying to come up with is a way to switch the path the sprite is following based on simple AI instructions. The real problem is, I don't want my game engine editor, to be tied up with over 100 different sprite paths, and in some situations the sprites might be better off as free moving agents, able to act more intelligently based on the player's behavior patterns...

But, for now.
What I have figured out is if I map the coordinates on a single screen by drawing a line using mouse input, I can set a frame skip value for sprite paths if paths happen to be clustered too far together.
And.. I can use a smart move command for sprite paths, so that they try to move from path point a to path point b, inbetween path nodes. That's a little harder. And alot of this seems like I'm over thinking it.

What I really want, is to be able to set sprite paths in large level areas. Let's say my level is 20,000 pixels long by 40,000 pixels tall. That's a BIG level. Think of the resoultion on a normal moniter.

Now what if I want a few sprites to specially move the entire length through my level, and then back again. I like to do everything in a virtual environment. If it's a matter of coordinates this is very memory efficient, and then I only draw the sprite if it is indeed on my screen. Except.. it still poses one big issue.

Editing:

It would take a very long time to scroll through the entire 2d world, and set up a path like that. So it's very time consuming. If I set shorter paths, like way points. And a general sprite direction for it to follow, it might work. This poses another problem still though! Suddenly, I'm letting random screen values control sprite movement, and that isn't good either. If I created level specific objects in which the sprites interacted with. Like say, platforms. I could set the sprites to walk on them, until they collided, then turn around. But again.. a path like this is even to simple. What if, I want the sprite to jump at specific points, and behave a very intricate way. I could set up a routine to simply interprete a set of actions, where areas the actions are performed outside of a path. IE Sprite action gets the privelage to over ride a path that is set.

In mario world, I noticed that sprite paths don't really exist. Sprites have specifically set behaviors, normally. So you get unreliable sprite spawns sometimes. I don't want that kind of thing happening in my engine, I want everything to be coordinate specific.
Again.. editing. and how to go about it.
Since, design plays a huge role in how a game actually works. I want to make sure that every feature in it is solid and doesn't leave any holes or anything to be wished for. I'm putting alot of time into just the routines I want to use. I'm still a long ways away from being able to make the game engine system I'm designing a reality. But it is possible and I'm determined.

Speaking of mario world...

It's hard to dis it, since for it's time it had so many excellent game engine features which these days are often over looked by people designing 2d games. Having a copy of a rom is illegal, so I understand. But, discussion wise.. Mario World uses an amazing range of internal sprite commands created out of assembly within it's engine, and I've looked at the higher level stuff it does. It's very interesting.

But again, to me mario world doesn't stand out as a standard for a 2d game I want to design. But the concepts based in it are pretty amazing. I wouldn't want my 2d engine to be that lossy. And if you have ever played a hack of mario world.. you'd know how it likes to drop sprites... or even not spawn them. Mind you, emulators aren't nearly as acurate as the hardware of the Snes.

Back to sprite pathing though..

If I created a path, that was very long for a sprite to follow. Then the sprite had to jump. I would have to pause the path the sprite was on.. now if the sprite moved too far from the path I couldn't just plot it back to where it's last path point was?...so I'd have to poll the array for the nearest continuation point.. IE the nearest node. And then have the sprite go from it's current point, back to the path it was on.

This is an incredibly awkward way of polling sprite behavior and I really don't like what it would result in..


So without further delay.

If anyone has any input, I'll gladly take it.

I'll post a code example below.


LemonWizard

#1
Code Example And Download



PlayBASIC Code: [Select]
; PROJECT : Project
; AUTHOR :
; CREATED : 2/26/2010
; EDITED : 6/24/2010
; ---------------------------------------------------------------------
openscreen 640, 480, 32, 1

SETFPS 120
;path program

;set the path

currentx=mousex()
currenty=mousey()
currentframe=1
dim framedata(currentframe, 3)
frametimer=timer()+10

start_test:
text 100, 100, "Press the mouse button and drag to create your path!"
text 100, 120, "Try to make it loop. Press the right mouse button when finished."


if leftmousebutton()
goto pathset
endif

goto start_test

pathset:
currentx=mousex()
currenty=mousey()
framedata(currentframe, 1)=currentx
framedata(currentframe, 2)=currenty
if leftmousebutton()
framedata(currentframe, 3)=color
currentframe=currentframe+1
redim framedata(currentframe, 3)
endif


if rightmousebutton()
pathplaytimer=timer()+50
cls rgb(0,0,0)
goto pathplay
endif

color=rgb(255,0,0)
ink color
if leftmousebutton()
circle currentx, currenty, 2, 1
endif

sync
;cls rgb(0,0,0)

goto pathset




pathplay:

writefile "path.pth", 1

writeint 1, currentframe
for temp=1 to currentframe
writeint 1, framedata(temp, 1)
writeint 1, framedata(temp, 2)
next temp
closefile 1


logo=loadnewfximage("kirby.png")
imagemaskcolour logo, rgb(255,255,255)
backdrop=loadnewfximage("222.jpg")
song=loadnewmusic("kdlboss.mid")
loopmusic song, true
playmusic song

speed=8
logox=500
logoy=0
xdirection=1 ;1=left 2=right
ydirection=2 ;1=up 2=down
kirbywalkingx=1
kirbywalkingy=350
kirbywalkingframe=1
kirbyrunningx=1
kirbyrunningy=300
kirbyrunningframe=1
floatx=0
floaty=25
floatframe=1

readfile "path.pth", 1 ;getting the frame data from the last path set
currentframe=readint(1)
redim framedata(currentframe, 2)
for temp=1 to currentframe
framedata(temp, 1)=readint(1)
framedata(temp, 2)=readint(1)
next temp
closefile 1

frametracker=1

dim walkright(4)
for temp=1 to 4
walkright(temp)=loadnewfximage("walk/walkright"+str$(temp)+".bmp" )
imagemaskcolour walkright(temp), rgb(255,255,255)
next temp

dim runright(8)
for temp=1 to 8
runright(temp)=loadnewfximage("run/runright"+str$(temp)+".bmp")
imagemaskcolour runright(temp), rgb(255,255,255)
next temp

dim kirbyfloat(4)
for temp=1 to 4
kirbyfloat(temp)=loadnewfximage("float/float"+str$(temp)+".bmp")
imagemaskcolour kirbyfloat(temp), rgb(255,255,255)
next temp



Scrollx#=1
main:
ScrollX#=Mod(ScrollX#+10,GetImageWidth(BackDrop))
Scrollx#=Scrollx#+10
TileIMage BackDrop,ScrollX#,0,false
;drawimage backdrop, 0, 0, 0
drawimage walkright(kirbywalkingframe), kirbywalkingx, kirbywalkingy, 1
drawimage logo, logox, logoy, 1
drawimage runright(kirbyrunningframe), kirbyrunningx, kirbyrunningy, 1
drawimage kirbyfloat(floatframe), floatx, floaty, 1


floatx=framedata(frametracker, 1)
floaty=framedata(frametracker, 2)
frametracker=frametracker+7


if frametracker>currentframe then frametracker=1
floatframe=floatframe+1
if floatframe>4 then floatframe=1
kirbyrunningframe=kirbyrunningframe+1
if kirbyrunningframe >8 then kirbyrunningframe=1
kirbyrunningx=kirbyrunningx+8
Login required to view complete source code




kevin

#2
Quote from: LemonWizard on June 24, 2010, 05:09:46 PM


Okay, after careful debate I decided I would share with the community because I think I am at the point where input is helpful.

I was fiddling around in pb one evening, late. I was trying to create a drawing app that was small and simple to use that had a rewind feature. To compliment my recent experiments in modding super mario world and using snes9x videos and playback to break the game or test for rom bugs.

Needless to say, it worked. I was trying to go for something like a frame by frame ram dump, so that values would basically be saved into an instance variable which had a lifespan of one frame when played back.
The game engine itself would just run the values through, and behave accordingly. Interesting concept which I'm still working on is giving my programs their own memory of the last few frames. For debugging purposes. Then, I thought to store a specific set of values in a long term array, which could then be played back through the engine frame by frame.


  I'm not really following what you're trying to do.  But If you really want to get into rom hacking, then you really need some knowledge the systems display hardware / formats and the good understanding of machine code.   Most emulators include a monitor to aid in this type of pursuit.



Quote
Eventually, all of this effort combined led me to create a path array for sprites. And what I found was a solution to a problem I've had with sprites for a while. How do I make them dynamically move? You see, I hadn't previously figured out how to make paths for sprites before this. I was trying to use a list of coordinates manually typed out and I hadn't thought to record them into an array using the mouse. Except.. the result for now is still a little unsatisfying since I can't yet make the paths span a larger screen. (One that is split up into a large 2d world)

  In a scrolling world game, the screen represents only a portion of the  larger world.    So generally the top left corner of the screen as we move through the world space, will represent the world coordinate of the top left pixel in the screen.    The mouse position is a screen coordinate, so to convert the mouse position from a screen coordinate into a world cord to simple add the current world position to the mouse.

   MouseWorldX =  WorldPositionX + MouseX()
   MouseWorldY =  WorldPositionY + MouseY()

  This gives up the position within world space the mouse is currently located.    


 Example.

PlayBASIC Code: [Select]
   ; ------------------------------------------
; Program Setup
; ------------------------------------------


WorldWidth=2000
WorldHeight=2000

; create an image to represent the world
WorldIMage=NewImage(WorldWidth,WorldHeight)

; fill the world image with circle, so we've something to look at
RenderToImage WorldImage
for lp=0 to 100
circlec rnd(worldwidth),rnd(worldHeight),rndrange(10,100),true,rndrgb()
next
rendertoscreen

; create a camera to view the world from a position
cam=newcamera()

; limit the cameras movement to withyin the range of the world
limitcamera cam,true
limitcamerabounds cam,0,0,worldwidth,worldheight


; ------------------------------------------
; start of main loop
; ------------------------------------------

Do

; draw the what the view sees, from the world
capturetoscene
clsscene
drawimage WorldImage,0,0,false
drawcamera cam

; ------------------------------------------
; move the camera position within the world
; ------------------------------------------
speed=2
if leftkey() then movecamera cam,-Speed,0
if rightkey() then movecamera cam,Speed,0
if upkey() then movecamera cam,0,-Speed
if downkey() then movecamera cam,0,Speed


; display the position of the camera within the world
; the camera's position is the top left coordindate of the screen
; within world space
Text 10,10,str$(GetCameraX(cam))+","+str$(GetCameraY(cam))


; -------------------------------------
; DRaw with the mouse on the world
; -------------------------------------
; if the mouse button is down, draw onto the world
if mousebutton()

; Calc the World coordinates of the mouse
MouseWorldX= GetCameraX(cam) + MouseX()
MouseWorldY= GetCameraY(cam) + MouseY()

; Use this coord to draw onto the world space, in this case is picture
rendertoimage WorldImage
dotc MouseWorldX,MouseWorldY,rndrgb()
rendertoscreen
endif

Sync
loop





Quote
The mainstay goal here, is to handle sprite pathing with either 2 methods.

 1-A value between 1 and 8, to allow for angled movement. Up, down left right, Upleft, Upright, downleft, downright.

 2-A value which is coordinate specific, in the next step.
This works sort of fine... but not quite. Since if I want intelligently behaving sprites AI has to be incorperated somehow.. so basically. I have to use different movement modes..

The solution I'm trying to come up with is a way to switch the path the sprite is following based on simple AI instructions. The real problem is, I don't want my game engine editor, to be tied up with over 100 different sprite paths, and in some situations the sprites might be better off as free moving agents, able to act more intelligently based on the player's behavior patterns...


   Most 2d games use some variation of state machine logic to control the game characters.   How complex this gets is really up the games requirements.  

   If you want characters to follow paths, but then make choices within this logic.  Then clearly the path is more a general reference to the character of where it's heading, rather than being tied to the path on a pixel by pixel basis.  

   The characters behavior logic will have to deal any situations as they occur.  For example,  imagine a large house (viewed from the above).  To make objects roam within the house freely,  we could make a set of paths that interconnect the rooms & hall ways.  A character can find it's way to another room by searching down a path list, looking for it's target.  However, knowing how to get there is one issue, another is interacting with doors and other characters (attack/talk whatever) along the way.



Quote
  What I really want, is to be able to set sprite paths in large level areas. Let's say my level is 20,000 pixels long by 40,000 pixels tall. That's a BIG level. Think of the resoultion on a normal moniter.

  Now what if I want a few sprites to specially move the entire length through my level, and then back again. I like to do everything in a virtual environment. If it's a matter of coordinates this is very memory efficient, and then I only draw the sprite if it is indeed on my screen. Except.. it still poses one big issue.


Editing:

It would take a very long time to scroll through the entire 2d world, and set up a path like that. So it's very time consuming. If I set shorter paths, like way points. And a general sprite direction for it to follow, it might work. This poses another problem still though! Suddenly, I'm letting random screen values control sprite movement, and that isn't good either. If I created level specific objects in which the sprites interacted with. Like say, platforms. I could set the sprites to walk on them, until they collided, then turn around. But again.. a path like this is even to simple. What if, I want the sprite to jump at specific points, and behave a very intricate way. I could set up a routine to simply interprete a set of actions, where areas the actions are performed outside of a path. IE Sprite action gets the privelage to over ride a path that is set.


  The path isn't the characters entire behavior, it's just part of it.  Like an objective say.  So things like dealing with environmental issues along the way (to it's objective),  such as jumping over a something,  waiting for an lift or a door to open... whatever, are part of the characters behavior process also.   So it's not blindly moving along the path from start to end, rather it's checking it's local environment for things that it has to deal with.  



Quote
In mario world, I noticed that sprite paths don't really exist. Sprites have specifically set behaviors, normally. So you get unreliable sprite spawns sometimes. I don't want that kind of thing happening in my engine, I want everything to be coordinate specific.
Again.. editing. and how to go about it.
Since, design plays a huge role in how a game actually works. I want to make sure that every feature in it is solid and doesn't leave any holes or anything to be wished for. I'm putting alot of time into just the routines I want to use. I'm still a long ways away from being able to make the game engine system I'm designing a reality. But it is possible and I'm determined.

  Things like spawn points certainly need a helping hand,  so there's generally 'spawn' entities or zones if you like within the world space, rather than just randomly dropping things into the world.  


Quote
Back to sprite pathing though..
If I created a path, that was very long for a sprite to follow. Then the sprite had to jump. I would have to pause the path the sprite was on.. now if the sprite moved too far from the path I couldn't just plot it back to where it's last path point was?...so I'd have to poll the array for the nearest continuation point.. IE the nearest node. And then have the sprite go from it's current point, back to the path it was on.

This is an incredibly awkward way of polling sprite behavior and I really don't like what it would result in..

 That's how it's done.