Post new topic    
Page 1, 2  »
Liquid Metal Slime
Send private message
Sidescroller Problems 
 PostFri Aug 22, 2014 9:38 pm
Send private message Reply with quote
Ok, so I know this is probably a terrible idea, but I'm trying to make a sidescroller using OHR, and a few things aren't going the way I want them to and I was wondering if anyone could help me. Instead of using a hero or NPC as the player, I loaded a walkabout sprite and I am manipulating it using the "set slice velocity" commands. My main reason for doing this is to have a custom walking animation, giving the sprite 2 idle frames (left and right) and 3 frames each for walking left or right. I don't want to have jumping, I don't really want to worry about that, I just want walking left and right and climbing ladders, which I will get to later. So far I've succeeded in making the character move left and right, change direction, but not animate.

I've set everything up similarly to the Baby Bob the Hamster demo, if that helps at all, and in my main loop it checks the player's velocity and then tells it to run through an animation based on which direction the sprite is moving.

Code:

$0="Animate"
         if(xv > 0) then(cycle right)

         if(xv < 0) then(cycle left)
         
         if(xv == 0) then(
            if(was right) then(
               set sprite frame(player,0)
            )
            else if(was left) then(
               set sprite frame(player,7)
            )
         )


And the scripts "cycle right" and "cycle left" are defined later in the file.

Code:

script, cycle right, begin

   set sprite frame(player,1)
   if(xv == 0 || xv < 0) then(
      was right := true
      was left := false
      exit script)
   wait(2)
   
   set sprite frame(player,2)
   if(xv == 0 || xv < 0) then(
      was right := true
      exit script)
   wait(2)
   
   set sprite frame(player,3)
   if(xv == 0 || xv < 0) then(
      was right := true
      exit script)
   wait(2)
   
   set sprite frame(player,2)
   if(xv == 0 || xv <0> 0) then(
      was left := true
      was right := false
      exit script)
   wait(2)

script, cycle left, begin

   set sprite frame(player,6)
   if(xv == 0 || xv > 0) then(
      was left := true
      was right := false
      exit script)
   wait(2)
   
   set sprite frame(player,5)
   if(xv == 0 || xv < 0) then(
      was left := true
      exit script)
   wait(2)
   
   set sprite frame(player,4)
   if(xv == 0 || xv < 0) then(
      was left := true
      exit script)
   wait(2)
   
   set sprite frame(player,5)
   if(xv == 0 || xv < 0) then(
      was left := true
      exit script)
   wait(2)
   
end


Right now, it only changes the sprite frame when the velocity is 0, so the sprite changes left and right, but never shows any of the other frames. I don't know if I'm putting things in the wrong places or if I'm just doing something completely wrong but if anyone has any ideas I'd love some insight.[/img]
My pronouns are they/them
Ps. I love my wife
Liquid Metal King Slime
Send private message
 
 PostFri Aug 22, 2014 9:54 pm
Send private message Reply with quote
There's no END at the end of the cycle right script ?
not sure if that would compile.

Other than that the flow seems to have some clear problems. Each time the script runs, it would only go to the first if command, and never make it to the others.

You're going to want to make a global variable to store the current frame number in so you can check for that when you're changing the current picture.


Oh, and I don't think it's a terrible idea to make a side scroller in the ohr at all. There's several side-scrollers made for the engine, some of which are current on the OUYA gaming console.

Play Tim-Tim "the mighty gnome"
Super Slime
Send private message
 
 PostFri Aug 22, 2014 10:12 pm
Send private message Reply with quote
As someone who's responsible for way too many OHR sidescrollers, I have to say that the limiting factor is the terrible framerate. 17 fps is fine for an RPG, but it's choppy and imprecise for a sidescroller. Framerate isn't something I usually pay attention to, but it's really noticeable in this case.
Mega Tact v1.1
Super Penguin Chef
Wizard Blocks
Metal King Slime
Send private message
 
 PostFri Aug 22, 2014 10:14 pm
Send private message Reply with quote
I might be wrong too, but doesn't the OHR use >> and <<for> and <That> and < are okay, but when the hell did that happen? I would swear it's been >> for yeeeeeears
Liquid Metal Slime
Send private message
 
 PostFri Aug 22, 2014 11:42 pm
Send private message Reply with quote
The end didn't copy and paste right, I'm not sure why. It is there, though, I assure you.

My reason for having the if statements there at all is to leave the animation if the player stops moving, so it doesn't keep going if they stop holding down the button. I was trying to preemptively prevent a problem, but I see now that I only created more.

The problem I've never been able to get around is the waiting within an animation. If it's in the main loop, it will make the whole game wait while it's animating something, but I don't know where else to put it. Should I make a separate loop as a map autorun script?
My pronouns are they/them
Ps. I love my wife
Liquid Metal King Slime
Send private message
 
 PostSat Aug 23, 2014 1:19 am
Send private message Reply with quote
You used to have to use >> and << but in the latest version you can use > and <

The "Disable HTML in this post" checkbox helps when posting script

The big problem here is that scripts can't run at the same time. When a script starts, all other scripts become frozen until it completes. This means you cannot write your cycle right and cycle left scripts in that way.

You should have one master loop. That master loop should have a single "wait(1)" and there should be no other wait commands.

In each pass of the main loop, you should call a script that updates the animation just one tick, and then ends. Does that make any sense?

If you want an example, there are plenty of better examples than Baby_Bob.rpg... in fact, I think that is the second oldest OHR sidescroller in existence.
Liquid Metal Slime
Send private message
 
 PostSat Aug 23, 2014 1:24 am
Send private message Reply with quote
Actually, that makes a lot of sense! I will try that out. Thank you guys, this is the first post I've ever made on here and it was super helpful. I'll post an update once I get it to work.
My pronouns are they/them
Ps. I love my wife
Liquid Metal Slime
Send private message
 
 PostSat Aug 23, 2014 4:09 am
Send private message Reply with quote
Not sure if it helps for sidescrollers, but you can fake simultaneous scripting if you use timers. The trick is to treat your timer like a wait command, so even though it can be extremely messy, it's effective. Entrepreneur: The Beginning uses a formula that assigns an x/y value to two global variables, and then continuously runs a timer until the NPC's coordinates matches them, then it terminates and triggers a new timed script that issues new commands that must then be matched before the next timer stops triggering. This way, it never has to worry about a wait locking up the script. This is why customers can approach the counter and move about the park using personal AI without causing too much of a scripting log jam. It's simple to do; you just need a little extra patience in navigating through your command needs.

So, if you're trying to check for left foot/right foot animation, you could just run two timers and change the frame when the designated timer expires. Just make sure you call the script to trigger that same timer again if the conditions to stop it haven't been met.

Hope that makes sense.

The key here to remember is that waits are what causes scripts to hang. Eliminating waits means eliminating hang, regardless of how many functions you're trying to accomplish at once. You still have to remember that a script has to finish before it will allow another to run, so it's best not to fake-multitask complicated actions, as it will cause navigation headaches. But because any script that has no wait runs immediately and ends just as quickly, the player will never know that something might be run out of order since, to him or her, it will all happen at once.
Place Obligatory Signature Here
Metal King Slime
Send private message
 
 PostSat Aug 23, 2014 9:53 am
Send private message Reply with quote
Using the slice velocity commands is a bit problematic because each game frame is processed in this order:
-check the keyboard, etc, state
-run scripts
-heroes, npcs, and slices update/move according to builtin behaviour like slice velocity
-draw the screen

That means that when you query slicex/y of a slice with non-zero velocity, you're not going to get the position that the slice is actually going to be, meaning that you detect collisions with other things a tick too later, unless you carefully take this into account. You can use the slice mvoement commands anyway, but will probably end up with some graphical glitches when bumping into walls... since you won't have jumping, I suspect this is acceptable.

Regarding timers, using a single main loop that contains the only wait command is the way to avoid needing timers. One use of timers, as Pepsi described, is to handle the situation where you want to have pauses (ie waits) in two commands at once.

Regarding the framerate, we're planning to hopefully make that customisable sometime soon. There's no point in holding up the next (quite near) release for that, so I'm not planning to get to that until soon afterwards.
Liquid Metal Slime
Send private message
 
 PostSat Aug 23, 2014 11:13 pm
Send private message Reply with quote
That explains why walls haven't been working correctly. Unfortunately I haven't even been able to animate the character yet.

I changed the way it checks and updates the current frame, but I'm still doing something wrong. In the main loop I have it update the frame if the velocity is not 0.

If the velocity is greater than or less than 0, it runs this script:

Code:

script, update frame, begin

   frame := get sprite frame(player)

   if(xv >> 0) then(
      switch(frame) do, begin
         case(1)
            set sprite frame(player,2)
            last frame := 1
            break
         case(2)
            if(last frame == 1) then(set sprite frame(player,3))
            else if(last frame == 3) then(set sprite frame(player,1))
            break
         case(3)
            set sprite frame(player,2)
            last frame := 3
            break
         case(else) set sprite frame(player, 1)
      end
   )
   else if(xv << 0) then(
      switch(frame) do, begin
         case(6)
            set sprite frame(player,5)
            last frame := 6
            break
         case(5)
            if(last frame == 6) then(set sprite frame(player,4))
            else if(last frame == 4) then(set sprite frame(player,6))
            break
         case(4)
            set sprite frame(player,5)
            last frame := 4
            break
         case(else) set sprite frame(player,6)
      end
   )
end


Perhaps it's what TMC said about the process order? Would the main loop catch if something's velocity is not 0?
My pronouns are they/them
Ps. I love my wife
Metal King Slime
Send private message
 
 PostSun Aug 24, 2014 5:05 am
Send private message Reply with quote
So what actually happens? That looks correct to me, so maybe the problem is elsewhere. Posting all your scripts could help.

You could handle the xv == 0 case in that script as well. I assume that you will want to change the frame to either 2 or 5 in that case.

Unlike C, in HamsterSpeak you don't need to put a break at the end of each case (they break out of the switch/case, so in effect they'll do nothing here).

No need to change to << and >> instead of < and >.
Liquid Metal Slime
Send private message
 
 PostSun Aug 24, 2014 7:45 am
Send private message Reply with quote
Yeah, that's a good point. Here's the whole thing:

Code:

global variable, begin
   0,game is active
   1,player
   2,want action
   3,want left
   4,want right
   5,want up
   6,want down
   7,xv
   8,yv
   9,was left
   10,was right
   11,x
   12,y
   13,frame
   14,last frame
   15,climbing
   16,pass
end


plotscript, main loop, begin
   
   initialize
   show string at(0,0,0)
   
   while(game is active) do, begin
      
      $0="Movement"
      if(want left) then(
         try left
      )
      if(want right) then(
         try right
      )
      
         if(want up) then(
            try up
         )
         if(want down) then(
            try down
         )
         if(want action) then(
            try action
         )
      
      
      $0="Animate"
         update frame

      $0="Camera"
      x := slice x(player)
      y := slice y(player)
      focus camera(x,y,5)
      
      $0="Reset"
      want left:=false
      want right:=false
      want up:=false
      want down:=false
      want action:=false
      
      $0="Wait"
      wait(1)
   end
   
end

script, initialize, begin
   suspend player
   put camera(0,80)
   
   game is active := true
   player := load walkabout sprite(6)
   set parent(player,lookup slice(sl:hero layer))
   frame := get sprite frame(player)
   x := slice X(player)
   y := slice Y(player)
   xv := get slice velocity x(player)
   yv := get slice velocity y(player)
   pass := northwall+southwall+eastwall+westwall
   
   put sprite(player,80,160)
   show value(slice x(player))
end

plotscript, keypress, begin
   if(key is pressed(key:left)) then(
      want left := true
      was left := true
      was right := false
   )
   if(key is pressed(key:right)) then(
      want right := true
      was right := true
      was left := false
   )
   if(key is pressed(key:up)) then(
      want up := true
   )
   if(key is pressed(key:down)) then(
      want down := true
   )
   if(key is pressed(key:z)) then(
      want action := true
   )
   if(key is pressed(key:esc)) then(
      game over
   )
end

script, try left, begin
   if(read pass block(x/20--1,y/20) == eastwall || read pass block(x/20--1,y/20) == westwall) then(
      play sound(3)
   )
   else(
      if(read pass block(x/20,y/20 +1) == northwall) then(
         replace walkabout sprite(player,6)
         set slice velocity x(player,-5,1)
         climbing := false
      )
   )
end

script, try right, begin
   if(read pass block(x/20+1,y/20) == eastwall || read pass block(x/20+1,y/20) == westwall) then(
      play sound(3)
   )
   else(
      if(read pass block(x/20,y/20 +1) == northwall) then(
         replace walkabout sprite(player,6)
         set slice velocity x(player,5,1)
         climbing := false
      )
   )
end

script, try up, begin
   if(climbing == false) then(
      if(read pass block(add(x,10)/20,y/20) == 16) then(
         replace walkabout sprite(player,7)
         set sprite frame(player,0)
      )
   )
   else(
      if(read pass block(add(x,10)/20,y/20 -- 1) == 16) then(
         climbing := true
         set slice velocity y(player,-5,4)
         climbing := false
      )
   )
end

script, try down, begin
   if(climbing == false) then(
      if(read pass block(add(x,10)/20,y/20 + 1) == 16) then(
         replace walkabout sprite(player,7)
         set sprite frame(player,0)
         climbing := true
         set slice velocity y(player,5,4)
         climbing := false
      )
   )
   else(
      if(read pass block(add(x,10)/20,y/20 + 1) == 16) then(
         climbing := true
         set slice velocity y(player,5,4)
         climbing := false
      )
   )
end

script, try action, begin
   
end

script, update frame, begin

   frame := get sprite frame(player)
   
   if(xv == 0) then(
            if(was right) then(
               set sprite frame(player,0)
            )
            else if(was left) then(
               set sprite frame(player,7)
            )
   )
   else if(xv >> 0) then(
      switch(frame) do, begin
         case(1)
            set sprite frame(player,2)
            last frame := 1
         case(2)
            if(last frame == 1) then(set sprite frame(player,3))
            else if(last frame == 3) then(set sprite frame(player,1))
         case(3)
            set sprite frame(player,2)
            last frame := 3
         case(else) set sprite frame(player, 1)
      end
   )
   else if(xv << 0) then(
      switch(frame) do, begin
         case(6)
            set sprite frame(player,5)
            last frame := 6
         case(5)
            if(last frame == 6) then(set sprite frame(player,4))
            else if(last frame == 4) then(set sprite frame(player,6))
         case(4)
            set sprite frame(player,5)
            last frame := 4
         case(else) set sprite frame(player,6)
      end
   )
end


And to answer your question, the sprite moves left and right and changes direction, but only shows those two frames.



I hope that image works. That's the sprite and its frames, that should clear up the frames.

P.S. It's DEFINITELY not a retextured megaman.
My pronouns are they/them
Ps. I love my wife
Metal King Slime
Send private message
 
 PostSun Aug 24, 2014 7:53 am
Send private message Reply with quote
By "those 2 frames" you seem to mean 2 and 5.

I see the problem now: 'last frame' isn't really initialised properly. In particular, if you switch direction then the old value isn't one of 4 or 6, or 1 or 3 respectively. The solution is simple, replace
Code:
 else if(last frame == 3) then(set sprite frame(player,1))

with
Code:
 else(set sprite frame(player,1))

and similarly in the other direction.

-----
I can think of at least 3 OHR sidescrollers that appeared before Baby Bob; it wasn't the 2nd. I still think that the Baby Bob scripts are a reasonable place to start, though everyone uses SS101 because it comes with far more features and Baby bob has been forgotten.
Liquid Metal Slime
Send private message
 
 PostSun Aug 24, 2014 8:44 am
Send private message Reply with quote
The two frames I meant were 0 and 7. Sorry for the confusion. It seems to think the velocity is always 0. That or I've called it incorrectly or something. I'm certain I've set something up wrong, I just don't know what it is. Maybe it is changing but changing back in the same tick so you can't see it change... As you may have noticed, I'm not very experienced with this.
My pronouns are they/them
Ps. I love my wife
Metal King Slime
Send private message
 
 PostSun Aug 24, 2014 3:30 pm
Send private message Reply with quote
Oh, I didn't bother to look at the other scripts before. I see that the only place that xv (and yv) are actually set is in the initialise script! Just add "xv := -5" after "set slice velocity x(player,-5,1)" and same in "try right".

There are more problems though, such as that x and y are only updated at the end of the main loop, adding an extra frame of delay to the movement. Looking at the original Baby Bob scripts I see that there are a lot of differences, and rereading now I see that you're only using them for reference rather than as a base. (Also, BB v1.2 had far more features and more comments than I remembered, so actually don't think SS101 has that much of an advantage.)

In the original Baby bob the "try left" etc scripts set vx to 0 if they are blocked by a wall, but you don't have that code. Also, they align the player to a tile edge when you bump into a wall (the "point to tile") script, i.e. you move as far as you can. Those scripts are pretty nasty and hard to understand; I suggest you look at SS101's scripts instead which are simpler, e.g.:

Code:
script, npc can left, npc, begin
  variable (nx)
  nx := (npc pixel x(npc)--10) / 20
  if(
    (readpassblock(nx,(npc pixel y(npc)) / 20), and, east wall)
    ||
    (readpassblock(nx,(npc pixel y(npc) + 19) / 20), and, east wall)
    ||
    (npc pixel x(npc)==0)
  ) then (
    variable(new x)
    new x := 0
    if (npc pixel x(npc),mod,20 >> 10) then (newx := 20)
    put npc(npc, npc pixel x(npc) -- (npc pixel x(npc),mod,20) + new x, npc pixel y(npc))

    return(false)
  )
  else (return(true))
)


Both BB and SS101 have acceleration, and you don't; I wonder whether you plan to add that or not. If you don't, and you just stick to speeds which are divisible into 2 (like 5), then you can simplify some things, like not needing alignment to tile boundaries.


I think that you're doing fine and can definitely work this out.
Display posts from previous:
Page 1, 2  »