cube movement... smooth movements..

BlitzPlus Forums/BlitzPlus Beginners Area/cube movement... smooth movements..

Apollonius(Posted 2006) [#1]
Let's say I create a cube, or load an image of a cube. I wana move it as follow: If I press a certain key it will move to the left. +5 Pixel to the left in like a few milliseconds, to make it look as smooth as possible. Teach me about timed movements, custom timers...

Like instead of doing +5 instantly I want it to do:
+1
do
+1
do
+1
do... ect, timed to look smoothly.

I'm not sure if I'm explaining this correctly... if you don't understand please tell me I'll try to clarify. Please help!


CS_TBL(Posted 2006) [#2]
timer=CreateTimer(50) ; for 50 fps

Repeat
  WaitEvent()
  If EventID()=$4001 ; timertick
    If EventSource()=timer ; optional, if you have more than 1 timer..
    ; update
    EndIf
  EndIf

  If EventID()=$803 quit=true ; windowclose
Until quit


So, each time you press a key just add +1 to your coordinate-variable, the updates go automatically.


Apollonius(Posted 2006) [#3]
I forgot to mention that I'm not working on an application, I'm working on learning 2D Game developpement.. I know it has to be done with timers, I don't know how to make them work yet.

I need it to do +5, but smoothly, and whatever direction, I just wana see how it could be done.

Smooth PLayer Movements is what I'm trying to figure out at this stage.


CS_TBL(Posted 2006) [#4]
Has nothing to do with apps or games. You're using Blitz+, rite? Take advantage of it.

Here's how you can combine events and 2d:

Graphics 640,480

timer=CreateTimer(50)

Repeat
	WaitEvent()
	
	If EventID()=$4001
		Plot Rnd(640),Rnd(480)
	EndIf	
	
	If EventID()=$101
		Cls
	EndIf
	Flip

Until KeyHit(1)
End



Apollonius(Posted 2006) [#5]
If EventID()=$4001
Plot Rnd(640),Rnd(480)
EndIf

So that would be like the main loop of the game? It would loop forever every 50 frames? Or something. If I wanted to make a custom timer how would I do it? Like after 10 seconds do this and that. Without having any interferance in the main loop, like without stoping it.

Having something flash and a count down from 10.. having two things working at the same time.. ? :o


CS_TBL(Posted 2006) [#6]
WaitEvent() waits for an event from the OS, which is like: buttonpresses, mousemoves, keyhits, timers, windowresize etc.
If nothing happens, then the 'programcounter' err.. imagine an arrow pointing where the program is in the source, then all that will stay at the WaitEvent() command. So, if something happens (an event occurs) then you simply have to determine what event it is. You do this by checking on several event properties, like
EventID() the type of event that occured
EventSource() where the event came from
EventData() sometimes there's extra data like a keycode
EventX(), EventY() coordinate on a canvas-gadget

etc. (see the manual)

You can have various timers running at the same time, this multitimer stuff may look alien, but they all just create events, that's all you'll have to be concerned about. So you can have various async timers at once!

What you were trying to do was polling. That's where you have a mainloop and in it you update the gamestatus, and do the gameupdate (draw stuff etc.) always, as fast as the program can.
Polling-based programming and Event-based programming are different things, and personally I **NEVER** ever want to go back to polling! In BMaxgui the eventsystem is even better, but alas.

So, to answer your question: you could see this $4001 as a mainloop yes, at 50 fps in this case.

However, if you put everything in there (game AI update and screen update) then there wouldn't be much of a difference with what you're doing now (apart from that I really don't like polling-timers). What you could do is have 2 timers, one timer triggers the game-AI updates (like 30fps) and another does the screen updates (like 60fps), another timer (at speed 1) could be a timer to trigger a real clock etc.

That would look like this:

Graphics 640,480
AItimer=CreateTimer(30)
GFXtimer=CreateTimer(60)
CLOCKtimer=CreateTimer(1)

Repeat
  WaitEvent()
  If EventID()=$4001
    If EventSource()=AItimer
      ; do the updates
    EndIf
    If EventSource()=GFXtimer
      ; do the screen update
      Flip
    EndIf
    If EventSource()=CLOCKtimer
      ; update the clock
    EndIf
  EndIf
Until KeyHit(1)


When a timerevent ($4001) happens, the program goes into that If-EndIf, next you check which timer it was by checking the EventSource() with your timers. So, if you were programming visually: checking on events is like having all the possible options on a large grid, and then you go narrowing the choices down until you have the right choise.
Logically it's best to narrow down in an efficient way by first filtering out the largest part of all the options.

So, this would work perfectly, but it's wrong.. :P
  WaitEvent()
  If EventSource()=AItimer
    If EventID()=$4001
      ; do the updates
    EndIf
  EndIf
  If EventSource()=GFXtimer
    If EventID()=$4001
      ; do the screen update
      Flip
    EndIf
  EndIf
  If EventSource()=CLOCKtimer
    If EventID()=$4001
      ; update the clock
    EndIf
  EndIf


it *would* be ok to first check on the EventSource() when you're checking all the canvas-actions in case you're using a canvas.. then you go about;
If EventSource()=MyCanvas
  If EventID()=$201
  EndIf
  If EventID()=$202
  EndIf
  If EventID()=$203
  EndIf
  If EventID()=$204
  EndIf
; etc.
EndIf



Apollonius(Posted 2006) [#7]
I'm not using any canvas, I'm making a normal 2D game, so that way I can learn how to make things work. I'm trying a small rpg... So I'll have to make all the menus then character movements and then mapping using tiles :)

But I'm still very far from this. Soo hard lol.. I like how you explain this, you should make a tutorial for stupid begginners teach types, looping, mapping and how things should be to be the most efficient. And I'm sure there would be less questions in here.

This was really helpful.

One question remains
AItimer=CreateTimer(30)
GFXtimer=CreateTimer(60)
CLOCKtimer=CreateTimer(1)

are those seconds or milliseconds?
so it refreshes every 60?


CS_TBL(Posted 2006) [#8]
The canvas was just an example. Your game could perfectly run in a window on a canvas btw. but that's for later..

timer units = hertz

so 1 = 1 tick per second, 60 = 60 ticks per second etc.


Apollonius(Posted 2006) [#9]
Another question for you, so now I got an AI loop, a GFX loop and a clock loop.. What would be the best way or the best place to start my game mechanism? Like if I wanted to make a menu, the menu codes of mouse over and detecting where the mouse is and all, this wouldnt go in AI nor the two other loops, where would that go?


CS_TBL(Posted 2006) [#10]
uh.. make a new timer? CTRLtimer=CreateTimer(30) for all the menus, buttons etc.

Tho you could just as well put all that control stuff in the game AI loop since that's also 30fps.. You shouldn't see those 'loops' as restricted area orso, it's just the place to update your game thingies at 30fps. That could include anything, *even* the screenupdates, if you would settle for 30fps. Usually you want more fps so 60fps would do.

Btw, you could as well do 60fps for evreything, AI and GFX ..

Really, try to make some GUI app orso, doesn't even have to be that special, but after a week of GUI'ing you'll completely understand events and timers!


Apollonius(Posted 2006) [#11]
Ok thanks, I prefer sticking to non-application things.

I didn't get the answer to my cube problems though, moving a cube by +1 every seconds up to like 20, without affecting the other loops. Lets say it's an AI.

I can't use delay 1000, this freezes the whole game.

delay 1000
cube_x + 1
delay 1000
cube_x + 1
... up to 20
delay 1000
cube_y + 1.. then I could turn.

How would you do that, I can think of a way with timers but to me it'd take like 20 timers lol


CS_TBL(Posted 2006) [#12]
The delay method is bad indeed. Here's a freshly hacked solution.. dunno if it could be improved, I don't care to bother actually .. it just works :P

Graphics 640,480

timer=CreateTimer(25)
repeatwalks=-1


Repeat
	WaitEvent()
	If KeyHit(200)
		repeatwalks=0
		direction=0 ; up
	EndIf
	If KeyHit(208)
		repeatwalks=0
		direction=1 ; down
	EndIf
	If KeyHit(203)
		repeatwalks=0
		direction=2 ; left
	EndIf
	If KeyHit(205)
		repeatwalks=0
		direction=3 ; right
	EndIf
	
	If EventID()=$4001
	
		If repeatwalks>=0
			repeatwalks=repeatwalks+1
			
			If repeatwalks<=5
				Select direction
					Case 0 y=y-1
					Case 1 y=y+1
					Case 2 x=x-1
					Case 3 x=x+1
				End Select
			Else
				repeatwalks=-1
			EndIf
		EndIf
		
		Cls
		
		For px=-8 To 8
			For py=-8 To 8
				Plot (x+px)*8,(y+py)*8
			Next
		Next
		Rect x*8,y*8,8,8,1
		

		f=f+1
		fx=Sin(f*3.0)*32
		fy=Cos(f*2.0)*32
		Rect 320+fx*8,240+fy*8,4,4,1
		
		Flip
	EndIf

Until KeyHit(1)
End



Apollonius(Posted 2006) [#13]
I like this example very much.
(I don't get the small flying cube's code but that's not important right now.) Thanks for your help your awesome!

One thing I noticed, if I slow the timer to 10, it's not very smooth, is that because it's not drawn fast enough, or because it's just too slow?

Is there any way to make it very slow but smooth without it being jumpy?


CS_TBL(Posted 2006) [#14]
The flying cube was purely to demonstrate multiple processes at the same time, all triggered by the same timer.

Lowering the timer amount means less fps, so logically things become course.

It may look bumpy because of the *8 in the x,y coordinates. If you want smooth steps over the same distance you simply gotta have more than 5 steps.. try:
If repeatwalks<=32

and change all the the *8 into *1 (better comment the grid out!)


Apollonius(Posted 2006) [#15]
This seems a little confusing, but eventually I'll get it, thanks! :)