Spherical forums

Sphere Development => Sphere Support => Map/Tileset Support => Topic started by: laserblue on May 12, 2013, 03:12:05 pm

Title: Programming a map animation
Post by: laserblue on May 12, 2013, 03:12:05 pm
  Is a loop involving Tileset (x,y, , tileindex, layer) the best way to show changes in a map layer or should I use a surface or something else? I have a simple sprite that moves across the screen leaving marks behind it. The layer is transparent over a base layer background and then as the sprite moves forward, the tiles for the marks are set in place. Would it be too blocky an entire tile at a time? I will add some pics I have soon.

Title: Re: Programming a map animation
Post by: Radnen on May 13, 2013, 01:45:09 pm
Huh, you're creating a farming simulator - that's neat. Are you going to stay with those lines? Because what you can do is use the Line() function in a map render script. You will need to indicate a start position and an end position as the tractor moves.

Code: (javascript) [Select]

var Points = [];      // the tilling field points.
var black = CreateColor(0, 0, 0); // line color.

function RenderLines()
{
  for (var i = 1; i < 0 g_lines.length; ++i) {
     Line(Points[i-1].x, Points[i]-1.y, Points[i].x, Points[i].y, black);
  }
}

var enter_down;  // handles a single key press.
var mode = false; // are we in tilling mode?
function UpdateLines()
{
  var key_down = IsKeyPressed(KEY_ENTER);

  if (key_down && !key_last) {
    if (!mode) {
      Points[0] = { x: GetPersonX("tractor"), y: GetPersonY("tractor")-4 };
      Points[1] = { x: GetPersonX("tractor"), y: GetPersonY("tractor")-4 };
      Points[2] = { x: GetPersonX("tractor"), y: GetPersonY("tractor")+4 };
      Points[3] = { x: GetPersonX("tractor"), y: GetPersonY("tractor")+4 };
    }
    var mode = !mode;
  }

  if (mode) {
      Points[1] = { x: GetPersonX("tractor"), y: GetPersonY("tractor")-4 };
      Points[3] = { x: GetPersonX("tractor"), y: GetPersonY("tractor")+4 };
  }

  key_last = key_down;
}

function game()
{
  // ...

  SetUpdateScript("UpdateLines()");
  SetRenderScript("RenderLines()");
  
  // ...

  MapEngine("my_map.rmp", 60);
}


That's how you can do that. Pressing enter puts the code into tilling mode, then it draws lines that indicates the tilling. Now if you want it to do something else, it's just a matter of not drawing the lines, but images instead. I hope you get all that, render scripts and update scripts are very powerful Sphere functions.

Edit: thanks for catching that Alpha123
Title: Re: Programming a map animation
Post by: alpha123 on May 13, 2013, 02:34:49 pm
I'd probably do this by SetTile()ing some tiles on a separate layer above the ground layer. This is more flexible than just using Line(), although also a bit more complicated.

Basically it would look like this:
Start with a ground layer and a completely transparent layer above that.
As the tractor moves, set the tile behind the tractor to a tile that is completely transparent except for the lines.
If the tractor turns, use a special turn tile instead.
Keep a vector of the tractor's current direction and use floor(tractorX / tileWidth) - directionX, floor(tractorY / tileHeight) - directionY to get the tile behind it. (Where directionX is 1 if the tractor is going east, -1 for west, directionY is 1 for south and -1 for north.)
When the direction vector changes, change the tile that you're using for the lines.

EDIT: Radnen, I think you mean
Code: (javascript) [Select]
SetUpdateScript("UpdateLines()");
SetRenderScript("RenderLines()");

instead of
Code: (javascript) [Select]
SetUpdateScript(UpdateLines());
SetRenderScript(RenderLines());

which will parse and run but not at all do what you expect.
Title: Re: Programming a map animation
Post by: Radnen on May 13, 2013, 03:45:52 pm
Alpha123: I think that's what he meant by "blocky": the tiles will turn on as you move per tile. My line idea was to try and show him how to use an input to toggle a behavior and to draw lines as the tractor moves. Of course, if he no longer decides to use lines then my idea will need updating.
Title: Re: Programming a map animation
Post by: alpha123 on May 14, 2013, 12:56:33 pm
Ah that's true, yours will look a lot smoother. The problem is handling the tractor turning.
Title: Re: Programming a map animation
Post by: laserblue on May 18, 2013, 05:15:03 pm
 :D It is NOT a FARMING Simulation.  :D Agricultural, maybe. I might add some sweaty hoers with red dew rags later as extras in the background as a tribute to Radnen's Pioneer. It's going to be a boring, non-violent, possibly educational, fantasy adventure game with puzzles as a Walter Mitty type character works at the Corn Breeding Research Station. "Une autre carte monsieur?"  First I am making static illustrations for a job write up and then animated scenes. I fixed up my tractor a bit yesterday so things are more symmetrical and rectangular. Still nowhere close to a 3D SimTractor. The tractor is marking aisles/paths for the Inbreeding Nursery ranges with a 2-disk marker implement. It's zoomed out to 0.5 scale. The beige bits are wooden stakes. Not sure top-down tractor perspective best. Easiest.
    Thank you everyone for your replies. You understood me Radnen. Thank you very much for posting that code. As soon as I figure out the syntax error I will try it out and post a video or stills. Missing ;? Missing ) ?  Bugs!
     I'll also try the tile by tile idea for comparison. I'm leaving the turning Spriteset frames and animation  for later. 
   
Title: Re: Programming a map animation
Post by: williammah on May 19, 2013, 02:08:01 am
Well that's an original concept lol. These simulator games or "so-and-so tycoon" games can get really addictive :D
Title: Re: Programming a map animation
Post by: laserblue on May 28, 2013, 12:57:12 pm
  I need some tutorial material on the animation loop and use of RenderScript, SetRenderScript and SetUpdateScript functions I can't get the RenderLines() code to work. I keep getting either a missing ; or ) syntax error. Line(x1, y1, x2, y2, color) works when values are inserted but the line runs through my stakes rather than behind them. I'm starting to wonder about using LineSeries, PointSeries and Surface objects. I'm looking through Sphere code but have not found some example code yet.
The code below using SetTile(x,y, layer, tile_index)) draws three sets of lines at a decent speed with wait(100) but is jerky at wait(500).  I tried putting it into a RenderLines() function but I got "Map engine not running" problems or missing } syntax errors.
    I also have tried putting in code for the tractor sprite movement. With AttachInput() it works ok but I want it to move by itself. When I add GetTileWidth() *5; it just runs off the screen instead of stopping after the fifth tile and I could not get it to synchonize with the lines very well but a speed of 5 was close. I have since revised the code by adding the move command between each line set loop and it looks good enough but is very linear, clunky coding. I need to learn more about the QueuePersonScript and QueuePersonCommand functions and where to put them in my code.

Code: (javascript) [Select]
// Show all stakes in untilled field - zoom out 
DetachCamera();

// Set view to show stakes on both sides
SetCameraX(600);
  SetCameraY(300);
 
 
 
  // Zoom view out to see all stakes
  SetLayerScaleFactorX(0, 0.5);
  SetLayerScaleFactorY(0, 0.5);
  SetLayerScaleFactorX(1, 0.5);
  SetLayerScaleFactorY(1, 0.5);
  SetLayerScaleFactorX(2, 0.5);
  SetLayerScaleFactorY(2, 0.5);
  SetLayerScaleFactorX(3, 0.5);
  SetLayerScaleFactorY(3, 0.5);
  SetLayerScaleFactorX(4, 0.5);
  SetLayerScaleFactorY(4, 0.5);
 
  // Show desired layers - 0 is base soil, 3 is stakes, 4 is tractor
  SetLayerVisible(0, true);
  SetLayerVisible(1, false);
  SetLayerVisible(2, false);
  SetLayerVisible(3, true);
  SetLayerVisible(4, true);
  SetLayerVisible(5, false);
 
  RenderMap();
    FlipScreen();
  wait(5000);

FadeOut(1000);

// Show marking of aisles/paths in field with tractor
  DetachCamera();
CreatePerson("George",'TopTractor.rss',true);
SetPersonLayer("George", 4);
SetPersonDirection("George","east");

SetPersonVisible("George", true);
 
SetPersonX("George", 50);
  SetPersonY("George", 600);


    
  SetLayerScaleFactorX(0, 0.5);
  SetLayerScaleFactorY(0, 0.5);
 
  SetLayerScaleFactorX(1, 0.5);
  SetLayerScaleFactorY(1, 0.5);
 
  SetLayerScaleFactorX(2, 0.5);
  SetLayerScaleFactorY(2, 0.5);
 
  SetLayerScaleFactorX(3, 0.5);
  SetLayerScaleFactorY(3, 0.5);
 
  SetLayerScaleFactorX(4, 0.5);
  SetLayerScaleFactorY(4, 0.5);
 

   //RenderLines();
  RenderMap();
   FlipScreen();
   wait(500)

   

  // Change map line tiles as sprite moves to right
 
    // Line(100, 600, 500, 600, black);
 
  CreatePerson("GeorgeEast2",'TopTractor.rss',true);
SetPersonLayer("GeorgeEast2", 4);
SetPersonDirection("GeorgeEast2","west");
SetPersonX("GeorgeEast2", 50);
  SetPersonY("GeorgeEast2", 152);
SetPersonVisible("GeorgeEast2", false);
  
   CreatePerson("GeorgeWest",'TopTractor.rss',true);
SetPersonLayer("GeorgeWest", 4);
SetPersonDirection("GeorgeWest","west");
SetPersonX("GeorgeWest", 700);
  SetPersonY("GeorgeWest", 376);
SetPersonVisible("GeorgeWest", false);
  
  
  for (i= 3; i< 46; i++) {
  SetTile(i, 37, 1, 26);
  SetTile(i, 38, 1, 25);
   
    SetPersonSpeed("George", 16);
    SetPersonDirection("George", "east");
    QueuePersonCommand("George", COMMAND_MOVE_EAST, true);
  
   
   // SetTile(3, 37, 1, 26) - first tile of upper line for first range as example
 
  // Tile positions for all lines
  // Bottom Lines: (3.37) to (46,37) and (3,38) to (46,38)
  // Middle Lines: (3,23) to (46,23) and (3,24) to (46,24)
  // Top Lines:    (3,9) to (46,9) and (3,10) to (46,10)
  
  SetLayerVisible(0, true);
  SetLayerVisible(1, true);
  SetLayerVisible(2, false);
  SetLayerVisible(3, true);
  SetLayerVisible(4, true);
 
  
  RenderMap();
  FlipScreen();
  wait(100);
  
      }
  SetPersonVisible("George", false);

for (k= 46; k> 3; k--) {
  SetTile(k, 23, 1, 26);
  SetTile(k, 24, 1, 25);
  
   SetPersonVisible("GeorgeWest", true);
   SetPersonSpeed("GeorgeWest", 17);
   QueuePersonCommand("GeorgeWest", COMMAND_MOVE_WEST, true);
  
  
  RenderMap();
   FlipScreen();
   wait(100);
    }  

   SetPersonVisible("GeorgeWest", false);
for (k= 3; k< 46; k++) {
  SetTile(k, 9, 1, 26);
  SetTile(k, 10, 1, 25);
   
    SetPersonVisible("GeorgeEast2", true);
    SetPersonSpeed("GeorgeEast2", 16);
    SetPersonDirection("GeorgeEast2", "east");
    QueuePersonCommand("GeorgeEast2", COMMAND_MOVE_EAST, true);
 
  
  RenderMap();
   FlipScreen();
    wait(100); 
       }   
    
     SetPersonVisible("GeorgeEast2", false);
     
   
  wait(1000)
  
SetLayerVisible(3, false);
  RenderMap();
    FlipScreen();
  wait(1000);
Title: Re: Programming a map animation
Post by: N E O on May 28, 2013, 02:33:59 pm
Your code calls UpdateMapEngine() between RenderMap() and FlipScreen(). If you make updates before RenderMap you should UpdateMapEngine before RenderMap; if you make updates after RenderMap, the updates AND UpdateMapEngine should technically be after FlipScreen so that the updated map is ready for the next RenderMap call.
Title: Re: Programming a map animation
Post by: laserblue on May 30, 2013, 12:48:24 pm
 Thanks NEO. I don't understand yet, exactly how the animation loop works. Most of the available code has RenderScript(); then FlipScreen(); and I just threw UpdateMapEngine(); in because it sounded good. I was thinking RenderMap would draw the map to the back buffer, UpdateMapEngine would update the map engine with any other info and then Flipscreen would show my map.  Commenting out all the UpdateMapEngine lines didn't affect anything probably because I have no applicable map entities to update. I thought the Sprite might be a map entity but I guess not. I'm working on understanding the coding VERY SLOWLY. Thank you for your patience and understanding.
Title: Re: Programming a map animation
Post by: N E O on May 30, 2013, 05:26:31 pm
Your understanding is so far correct: RenderMap does indeed draw the current map to the back buffer, UpdateMapEngine force-updates the map engine one step. It's that RenderMap does NOT update the map before blitting to the back buffer, so all the camera setting and layer updating don't take effect before the map is buffered.

If anything changes on a map, the map engine must be updated either manually or automatically or else RenderMap won't see the updates in time.
Title: Re: Programming a map animation
Post by: laserblue on September 23, 2013, 12:19:46 pm
Here is a video of what I am working towards
http://www.youtube.com/watch?v=BxIMZLlFiS0&feature=c4-overview&list=UU7OaeQ60hSBQ80yjGsXrV8A (http://www.youtube.com/watch?v=BxIMZLlFiS0&feature=c4-overview&list=UU7OaeQ60hSBQ80yjGsXrV8A).

I used SetTile to change tiles from unmarked to marked. It was difficult to match the speeds of the lined tiles and the sprite especially for the second set of lines. I am now backing up and trying to get the Lines function to work with UpdateScript and RenderScript. So far I keep getting a syntax error stating that a semicolon is missing after the for loop.

Code: [Select]
 for (var i= 0; i<0 g_lines.length; ++i; ) {
     Line(Points[i-1].x, Points[i]-1.y, Points[i].x, Points[i].y, black); ] 
         }
    }

   I put SetUpdateScript and SetRenderScript  in main.js. I call my Intro function and declare a Points array and a colour for the pixels making up the line. I have a RenderLines function and an UpdateLines function. In my intro function I am going to have a RenderMap, FlipScreen, THEN UpdateMap (?). 
  
Title: Re: Programming a map animation
Post by: N E O on September 23, 2013, 04:04:05 pm
Check the y coordinate of the first point (the -1 looks to be outside the [ ]) and remove the ] at the end of the line.
Title: Re: Programming a map animation
Post by: Fat Cerberus on September 23, 2013, 11:18:25 pm
Also remove that last semicolon in the for clause, and there appears to be an extra close brace.
Title: Re: Programming a map animation
Post by: Flying Jester on September 24, 2013, 02:03:18 am
Code: [Select]
 
for (var i = 1; i < g_lines.length; i++) {
     Line(Points[i-1].x, Points[i-1].y, Points[i].x, Points[i].y, black);      
}


That looks more like what I would expect.
Title: Re: Programming a map animation
Post by: laserblue on October 18, 2013, 12:56:00 pm
 Radnen's idea of a tilling/write mode bound to the Enter key and the position of my tractor sprite was too complex for me.  I made a video using the tile changing method but the code is very linear. Now I have backed up to square one. I want to use SetUpdateScript("UpdateLines()"); and SetRenderScript("RenderLines()"); . I can get a line of any colour on a blank screen with no map by creating color variables and using the line command. I can get a line that appears over a map by putting the line command after RenderMap. Other locations in the code don't seem to have any effect.  That line seems to be on a top layer or unconnected to the map since it obscures a layer that should be above it eventually. I'm not going to worry about that for now as it adds too much complexity. I noticed that UpdateMap can be commented out with no effect when I run the code again, unless I run code that draws a line and no map by commenting out RenderMap(). Then I need UpdateMap uncommented to get the map and line to display together again. If I use Getkey in the code to stall display, the lines disappear as soon as I hit a key. Now I'm just trying to get a simple RenderLine function for a line segment an and UpdateLine function working. I'm getting UpdateLine is not defined and having trouble figuring out how to update a line endpoint in the UpdateLine function.  The code has to do some kind of count of the number of times the updateline function is called because each frame, the x- coordinate value in the UpdateLine function must be increased by one or maybe a few more. 
Title: Re: Programming a map animation
Post by: Harry Bo21 on October 22, 2013, 04:30:01 pm
If im right in what you want he finished product to look like, it sounds like ou would need some kind of array storing nodes (co-ords). Use MapToScreen() to connect the nodes with lines.

To avoid literally every node connecting (to allow for mutliple instances) you would need multiple arrays or some kind of check to run

P.S I am finding it very hard to read your posts, make sure to break it up with paragraphs and post example code

**EXTRA** dont forget to check out the API within sphere. It looked confusing to me at first, but if you do a couple of basic projects just to see how different functions work you will pick up a lot very quickly.

Link for Arrays - http://www.hunlock.com/blogs/Mastering_Javascript_Arrays (http://www.hunlock.com/blogs/Mastering_Javascript_Arrays)

***EDIT*** looking at you code behnd the picture, you are setting the X,Y for the lines, therefore they will ALWAYS appear there, they are done via screen co-ords so will not support scrolling the map and they dissapear as the code is run up to GETKEY() and no further. When you hit the key it drops the above code, you need update and render functions and some kind of variable storage