Controlling a moving brush
Controlling a moving brush
Hi all, I have a question for you... If I want to do something like tetris - a brush is moving from top of the screen to the bottom and while it is moving i want to have a chance to move it by 20 pixels to the left and right by pressing a key , which is the best and the fastest technique ? I use this : i am repeatedly calling AsyncDrawFrame which moves the brush by one pixel down and for keypressing test i use IsKeyDown command - and it works good and it is fast - but maybe too fast sometimes... even if i press the key slightly the brush sometimes moves by 40 pixels insteads of 20... thanx pecaN
Re: Controlling a moving brush
Use delta timing to control the update speed of a brush. Look at My prototype game template with game state manager thread in this forum...
- airsoftsoftwair
- Posts: 5887
- Joined: Fri Feb 12, 2010 2:33 pm
- Location: Germany
- Contact:
Re: Controlling a moving brush
Do not use AsyncDrawFrame() for this. It's much better to do this with sprites using DisplaySprite() or a double buffered display.
Re: Controlling a moving brush
Here is a simple example to get you started:
You need my game template:
Code: Select all
;
; Simple blocks in Hollywood
;
@DISPLAY {Width = 350, Height = 360, Title = "Simple Blocks"}
Const #BLOCKSIZE = 16
; Include game framework
@INCLUDE "game.hws"
; Setup
Function game.load()
move_delay = 0
fall_delay = 0
game:setUpdateRate(60) ; set update rate
map:init()
shapes:init()
EndFunction
; Draw
Function game.draw()
Cls()
map:draw()
piece:draw()
EndFunction
; Update
Function game.update(dt)
move_delay = move_delay + dt
If move_delay >= 0.1
piece:move()
move_delay = 0
EndIf
fall_delay = fall_delay + dt
If fall_delay >= 0.4
piece:fall()
fall_delay = 0
EndIf
If IsKeyDown("ESC") Then End
EndFunction
;------------------------------------------------------------------------------------------
map = {}
Function map:init()
self.map = {}
map[-5] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
map[-4] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[-3] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[-2] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[-1] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[0] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[1] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[2] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[3] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[4] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[5] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[6] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[7] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[8] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[9] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[10] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[11] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[13] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[14] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[15] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[16] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[17] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[18] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[19] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[20] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[21] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
map[22] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
EndFunction
Function map:draw()
SetFillStyle(#FILLCOLOR)
For Local i = 1 To 21
For Local j = 0 To 21
Box(j * #BLOCKSIZE, i * #BLOCKSIZE, #BLOCKSIZE, #BLOCKSIZE, map[i][j])
Next
Next
SetFillStyle(#FILLNONE)
Box( #BLOCKSIZE-1, 0, 20 * #BLOCKSIZE + 2, 22 * #BLOCKSIZE + 1, #WHITE)
EndFunction
shapes = {}
shapes.shapes = {}
Function shapes:init()
Local shape = { coords = { { { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 2, y = 1 }, { x = 3, y = 1 } },
{ { x = 1, y = 0 }, { x = 1, y = 1 }, { x = 1, y = 2 }, { x = 1, y = 3 } } },
color = #RED }
InsertItem(self.shapes, shape)
Local shape = { coords = { { { x = 0, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 0 }, { x = 1, y = 1 } } },
color = #OLIVE }
InsertItem(self.shapes, shape)
Local shape = { coords = { { { x = 1, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 2, y = 1 } },
{ { x = 1, y = 0 }, { x = 1, y = 1 }, { x = 2, y = 1 }, { x = 1, y = 2 } },
{ { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 2, y = 1 }, { x = 1, y = 2 } },
{ { x = 1, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 1, y = 2 } } },
color = #TEAL }
InsertItem(self.shapes, shape)
Local shape = { coords = { { { x = 0, y = 0 }, { x = 1, y = 0 }, { x = 1, y = 1 }, { x = 2, y = 1 } },
{ { x = 1, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 0, y = 2 } } },
color = #PURPLE }
InsertItem(self.shapes, shape)
Local shape = { coords = { { { x = 1, y = 0 }, { x = 2, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 } },
{ { x = 0, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 1, y = 2 } } },
color = #BLUE }
InsertItem(self.shapes, shape)
Local shape = { coords = { { { x = 2, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 2, y = 1 } },
{ { x = 0, y = 0 }, { x = 0, y = 1 }, { x = 0, y = 2 }, { x = 1, y = 2 } },
{ { x = 0, y = 0 }, { x = 1, y = 0 }, { x = 2, y = 0 }, { x = 0, y = 1 } },
{ { x = 0, y = 0 }, { x = 1, y = 0 }, { x = 1, y = 1 }, { x = 1, y = 2 } } },
color = #NAVY }
InsertItem(self.shapes, shape)
Local shape = { coords = { { { x = 0, y = 0 }, { x = 1, y = 0 }, { x = 2, y = 0 }, { x = 2, y = 1 } },
{ { x = 1, y = 0 }, { x = 1, y = 1 }, { x = 0, y = 2 }, { x = 1, y = 2 } },
{ { x = 0, y = 0 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 2, y = 1 } },
{ { x = 0, y = 0 }, { x = 1, y = 0 }, { x = 0, y = 1 }, { x = 0, y = 2 } } },
color = #AQUA }
InsertItem(self.shapes, shape)
EndFunction
piece = {}
piece.id = 0
piece.x = 1
piece.y = -4
piece.rotation = 0
Function piece:fall()
Local ny = self.y + 1
Local i, v = NextItem(shapes.shapes[self.id].coords[self.rotation])
While GetType(i) <> #NIL
If map[ny + shapes.shapes[self.id].coords[self.rotation][i].y][self.x + shapes.shapes[self.id].coords[self.rotation][i].x] <> 0
Local ii, vv = NextItem(shapes.shapes[self.id].coords[self.rotation])
While GetType(ii) <> #NIL
map[self.y + shapes.shapes[self.id].coords[self.rotation][ii].y][self.x + shapes.shapes[self.id].coords[self.rotation][ii].x] = shapes.shapes[self.id].color
ii, vv = NextItem(shapes.shapes[self.id].coords[self.rotation], ii)
Wend
self.id = Rnd(ListItems(shapes.shapes))
self.rotation = Rnd(ListItems(shapes.shapes[self.id].coords))
self.y = -4
self.x = Rnd(20) + 1
ny = self.y
Break
EndIf
i, v = NextItem(shapes.shapes[self.id].coords[self.rotation], i)
Wend
self.y = ny
EndFunction
Function piece:rotate()
Local nr = self.rotation + 1
nr = Wrap(nr, 0, ListItems(shapes.shapes[self.id].coords))
Local i, v = NextItem(shapes.shapes[self.id].coords[nr])
While GetType(i) <> #NIL
If map[self.y + shapes.shapes[self.id].coords[nr][i].y][self.x + shapes.shapes[self.id].coords[nr][i].x] <> 0
nr = self.rotation
Break
EndIf
i, v = NextItem(shapes.shapes[self.id].coords[nr], i)
Wend
self.rotation = nr
EndFunction
Function piece:move()
Local nx
If IsKeyDown("UP") Then piece:rotate()
If IsKeyDown("LEFT")
nx = self.x - 1
Local i, v = NextItem(shapes.shapes[self.id].coords[self.rotation])
While GetType(i) <> #NIL
If map[self.y + shapes.shapes[self.id].coords[self.rotation][i].y][nx + shapes.shapes[self.id].coords[self.rotation][i].x] <> 0
nx = self.x
Break
EndIf
i, v = NextItem(shapes.shapes[self.id].coords[self.rotation], i)
Wend
self.x = nx
ElseIf IsKeyDown("RIGHT")
nx = self.x + 1
Local i, v = NextItem(shapes.shapes[self.id].coords[self.rotation])
While GetType(i) <> #NIL
If map[self.y + shapes.shapes[self.id].coords[self.rotation][i].y][nx + shapes.shapes[self.id].coords[self.rotation][i].x] <> 0
nx = self.x
Break
EndIf
i, v = NextItem(shapes.shapes[self.id].coords[self.rotation], i)
Wend
self.x = nx
EndIf
EndFunction
Function piece:draw()
SetFillStyle(#FILLCOLOR)
Local i, v = NextItem(shapes.shapes[self.id].coords[self.rotation])
While GetType(i) <> #NIL
Box((self.x + shapes.shapes[self.id].coords[self.rotation][i].x) * #BLOCKSIZE, (self.y + shapes.shapes[self.id].coords[self.rotation][i].y) * #BLOCKSIZE, #BLOCKSIZE, #BLOCKSIZE, shapes.shapes[self.id].color)
i, v = NextItem(shapes.shapes[self.id].coords[self.rotation], i)
Wend
EndFunction
; Go!
game:go()
Code: Select all
;
; Game template module: game.hws
;
game = {}
game.updateRate = 20 ; Default to 20 millisec = 50 fps.
game.dt = 0
game.fps = 0
; Game setup function for the user.
Function game.load()
; Our game must override this dummy function.
EndFunction
; Game update function for the user
Function game.update(dt)
; Our game must override this dummy function.
EndFunction
; Game draw frame function for the user
Function game.draw()
; Our game must override this dummy function.
EndFunction
; Our game framework init function. Calls just user game setup function for now
; and starts double buffering.
Function game.init()
game.load()
BeginDoubleBuffer()
EndFunction
; Basic game loop function for our framework.
Function game.loop(dt)
If game.state.event$ = "init" Or game.state.event$ = "update"
game.state.event$ = "draw"
If RawGet(game.state.states[game.state.state], "draw") Then game.state.states[game.state.state].draw()
Flip()
EndIf
If game.state.event$ = "draw"
game.state.event$ = "update"
If RawGet(game.state.states[game.state.state], "update") Then game.state.states[game.state.state].update(dt)
EndIf
EndFunction
; Set update rate for the game.
Function game:setUpdateRate(fps)
self.updateRate = 1000 / fps
EndFunction
; Get the current fps-rate.
Function game:getFPS()
Return(Round(1000 / (self.dt * 1000)))
EndFunction
; Runs the game, handles calling the game loop and timing.
Function game.run()
StartTimer(1)
StartTimer(2)
Repeat
; Try to lock the frame update rate to game.updateRate
WaitTimer(1, game.updateRate)
; Get the actual time it took to update the frame.
Local ftime = GetTimer(2)
ResetTimer(2)
; Delta time in seconds between the two last frames.
game.dt = game.updateRate / 1000 * ftime / game.updateRate
game.loop(game.dt)
Forever
EndFunction
Function game:go()
self.init()
self.run()
EndFunction
; Simple game state manager
game.state = {}
game.state.states = {}
game.state.states[0] = {} ; Default state
game.state.states[0].update = Function (dt) game.update(dt) EndFunction
game.state.states[0].draw = Function () game.draw() EndFunction
game.state.state = 0
game.state.event$ = "init" ; Start in init event.
game.state.ids = {}
; Registers new game state by name.
Function game.state:register(statename, state)
self.states[statename] = state
InsertItem(self.ids, statename)
EndFunction
; Remove game state from manager by state name.
Function game.state:remove(statename)
self.states[statename] = {}
Local i, v = NextItem(self.ids)
While GetType(i) <> #NIL
If self.ids[i] = statename Then RemoveItem(self.ids, i)
i, v = NextItem(self.ids, i)
Wend
EndFunction
; Clears all states from manager except default state.
Function game.state:clear()
Local i, v = NextItem(self.ids)
While GetType(i) <> #NIL
self.states[v] = {}
i, v = NextItem(self.ids, i)
Wend
self.ids = {}
EndFunction
; Set active game state by name
Function game.state:set(statename)
self.state = statename
self.event$ = "init"
If RawGet(self.states[self.state], "init") Then self.states[self.state].init()
EndFunction
; Get the name of a currently active game state
Function game.state:get()
Return(self.state)
EndFunction
; Get the currently active event of a game state
Function game.state:getEvent()
Return(self.event$)
EndFunction
Re: Controlling a moving brush
Thx for your replies guys ! As always, the solution was quite easy - just put ResetKeyStates() command after each IsKeyDown() ... i totally overlooked this command in the docs...
now it works good and controlling is not so sensitive...
@jalih : thx for sourcecode, will try it later
@Andreas : i know you recommend sprites for twtris like game in the docs but there is a problem - there are MANY sprites on the screen so i need to free them from memory but this is not possible because if a sprite is freed it is also deleted from screen and i don't want this... so i will probably have to use brushes...
@jalih : thx for sourcecode, will try it later
@Andreas : i know you recommend sprites for twtris like game in the docs but there is a problem - there are MANY sprites on the screen so i need to free them from memory but this is not possible because if a sprite is freed it is also deleted from screen and i don't want this... so i will probably have to use brushes...