How to use sprites+canvas on the same time? Like Linerider

Just starting out? Need help? Post your questions and find answers here.
T4r4ntul4
Enthusiast
Enthusiast
Posts: 118
Joined: Tue Mar 04, 2014 4:15 pm
Location: Netherlands

How to use sprites+canvas on the same time? Like Linerider

Post by T4r4ntul4 »

Hey all,

How can i use Canvas gadget to move realtime sprites? Just like a game engine?
What i try to do is to make some sort of linerider, i want to draw on the canvas gadget, and sprites needs to bump against it (and change direction).

Can this be done in canvas gadget only?
Or do i need the 2D engine for this? IF thats the case, how do i paint in 2D and sprites will interact with it?

Thanks for your thoughts!
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: How to use sprites+canvas on the same time? Like Linerid

Post by netmaestro »

It seems like a project entirely suited to a windowed screen using sprites and testing collisions - what do you want the canvas for?
BERESHEIT
T4r4ntul4
Enthusiast
Enthusiast
Posts: 118
Joined: Tue Mar 04, 2014 4:15 pm
Location: Netherlands

Re: How to use sprites+canvas on the same time? Like Linerid

Post by T4r4ntul4 »

To draw lines and thicker lines, and when a sprite or something bumps into it, it will carve that line away (per few pixels at a time). (if you understand what i mean)

So my thought was that i needed canvas or image gadget for the drawing part. and the sprite voor moving sprites to locations. and lines on the canvas/image acts like a border.

I dont know how i can 2D draw in windowed screen as you can in canvas/image gadget.


edit: i want to draw realtime, when the sprites are moving on the canvas/image.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: How to use sprites+canvas on the same time? Like Linerid

Post by netmaestro »

Your options are to use either the canvas or a windowed screen as there is no way to combine them. All 2DDrawing commands that are available for CanvasOutput() are also available for SpriteOutput() and ScreenOutput(). The only thing CanvasOutput() has that isn't available in the windowed screen is vector drawing. If you don't need that there's no need to consider the canvas further. The canvas lacks one capability vital to your project, sprite collision testing. Draw your lines using large transparent sprites, your cars or sleds as sprites also, and the command SpritePixelCollision() makes your job easy. I wouldn't want to tackle collision testing on a canvas gadget, that would be a monumental task. Here's a simple demo:

Code: Select all

OpenWindow(0,0,0,640,480,"Sprite collision demo",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
InitSprite()
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0,#PB_Screen_WaitSynchronization)
CreateSprite(0,640,480,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(0))
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0,0,640,480,RGBA(235,235,235,255))
  DrawingMode(#PB_2DDrawing_AllChannels|#PB_2DDrawing_Outlined)
  x=200:y=-10
  While y<480+10
    Circle(x,y,7,RGBA(255,0,0,255))
    y+1
    If y%2=0
      x+1
    EndIf
  Wend
  
StopDrawing()
CreateSprite(1,64,64,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(1))
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0,0,64,64,RGBA(235,235,235,255))
  Circle(32,32,30,RGBA(0,0,255,255))
StopDrawing()
TransparentSpriteColor(0,RGBA(235,235,235,255))
TransparentSpriteColor(1,RGBA(235,235,235,255))

x=0:y=220:fwd=1
Repeat
  ev=WindowEvent()
  If ev=#PB_Event_CloseWindow
    End
  EndIf
  ClearScreen(RGB(235,235,235))
  DisplayTransparentSprite(0,0,0)
  If SpritePixelCollision(1,x,y,0,0,0) Or x<0
   fwd=1-fwd
  EndIf
  If fwd:x+2:Else:x-2:EndIf
  DisplayTransparentSprite(1,x,y)
  FlipBuffers()
ForEver
This simple program would be much harder to write without the command SpritePixelCollision().

If vector drawing is important to you, the only solution I can think of would be to create your graphics on images and then affect those images to sprite objects. Of course, bites out of lines would have to occur to the image and the sprite updated with the new image.
BERESHEIT
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: How to use sprites+canvas on the same time? Like Linerid

Post by walbus »

Here you can found all you want, i think :wink:
This is a complete Breakout

Code: Select all

EnableExplicit
Define copyright$="www.nachtoptik.de",version$="1.1i" ; Break out - Author W.Albus - www.nachtoptik.de
Define beep_0,beep_1,beep_2,stepp_0,max_levels,ball_x,ball_y,ball_y_1,max_balls,max_balls_1
Define clinker,clinker_1,racket_width,racket_height,racket_pos,racket_moving,win_x,win_y,animation_speed
Define mouse_x,wait_for_speed_up,swapping,moving_a,moving_b,count,i,ii,iii,speed_up,stepp_old
Global timer_event_1,stepp,stepp_1,go_x,go_y

#sound=0 ; If you want sound - load your own 3 "Beep" Sound Files and set #sound=1
CompilerIf #sound
  #sound_0="beep_0.wav" ; Set here then the Path´s to the Soundfiles
  #sound_1="beep_1.wav"
  #sound_2="beep_2.wav"
  DataSection
    beep_0: :IncludeBinary #sound_0
    beep_1: :IncludeBinary #sound_1
    beep_2: :IncludeBinary #sound_2
  EndDataSection
  InitSound() : CatchSound(0,?beep_0) : CatchSound(1,?beep_1) : CatchSound(2,?beep_2)
  If IsSound(0)=0 Or IsSound(1)=0 Or IsSound(2)=0
    MessageRequester("Error","Can not init Sound",0) 
    End
  EndIf
  Macro play_sound(sound)
    PlaySound(sound)
  EndMacro
CompilerElse
  Macro play_sound(sound)
  EndMacro
CompilerEndIf

; ------------------------------- User editable Parameter´s -------------------------------
stepp_0=6       ; Speed - Start Value, from 3 up to max Levels (12) - Speed automatically add at times stepp_0 /3
max_levels=12   ; Maximal Level´s - Ball Speed add automaticaly from Level to Level
max_balls=5     ; Amount Ball´s in each Level
racket_width=70 ; Racket width
win_y=730       ; Window Y - resizable
; -----------------------------------------------------------------------------------------

animation_speed=10 ; I think, good so for the moostly Computer´s - Handbrake for very quickly Computer´s
win_x=1200         ; Window width - fix
ball_x=0           ; Startpoint Ball X
ball_y_1=216       ; Startpoint Ball Y
stepp_1=stepp_0
ball_y=ball_y_1
clinker=179
max_balls_1=max_balls*15
Dim clinker (clinker,1)

Enumeration 500
  #rotor_1 : #rotor_2 : #rotor_3
  #millstone_left : #millstone_right
  #speedpoint_left : #speedpoint_right
  #racket_0 : #racket_1 : #black_racket
  #ball
EndEnumeration

If InitMouse()=0
  MessageRequester("Error","Can´t init Mouse",0)
  End
EndIf

If Not LoadFont(0, "Arial", 24,#PB_Font_Bold)
  MessageRequester("Error","Can´t load Font Arial",0)
  End
EndIf

Procedure coloring_clinker(clinker,clinker_color)
  StartDrawing(SpriteOutput(clinker))
  FrontColor(clinker_color)
  DrawingMode(#PB_2DDrawing_Gradient)
  LinearGradient (0,0,0,16)
  Box(0,0,32,8)
  FrontColor(0)
  BackColor(clinker_color)
  Box(0,8,32,8)
  StopDrawing()
EndProcedure

Procedure display_and_rotate_sprite(sprite,x,y,angle)
  RotateSprite(sprite,angle,#PB_Relative)
  DisplaySprite(sprite,x,y) 
EndProcedure

Procedure timer_events()
  Select EventTimer()
    Case 1
      timer_event_1=1
    Case 2
      If stepp<stepp_1 
        stepp+1
        go_x=stepp : go_y=stepp
      EndIf
  EndSelect
EndProcedure

Macro collision_rotor(rotor,divisor,add_count)
  If SpriteCollision(rotor,win_x divisor -16,20,#ball,ball_x,ball_y) 
    If ball_x>win_x divisor
      go_x=stepp 
    Else
      go_x=-stepp 
    EndIf
    count+add_count
    play_sound(2)
  EndIf
EndMacro

OpenWindow(0,0,0,win_x,win_y,"Breakout - created & © Werner Albus - "+copyright$+" - Free distribution is allowed - Fee-based distribution prohibited - Quiet With ESC  - v"+version$,#PB_Window_SystemMenu | #PB_Window_ScreenCentered)

If InitSprite()=0 Or InitKeyboard()=0 Or OpenWindowedScreen(WindowID(0),0,0,win_x,win_y,0,0,0,#PB_Screen_WaitSynchronization)=0
  MessageRequester("Error","Can´t init Spritesystem",0)
  End
EndIf

AddWindowTimer(0,1,animation_speed) ; Handbrake for very quickly Computer´s:-)
AddWindowTimer(0,2,40) ; Accelerate Speed on Start - is this value bigger, stepp_0 must reduce
BindEvent(#PB_Event_Timer, @timer_events())

OpenWindowedScreen(WindowID(0),0,0,win_x,win_y)
ExamineKeyboard()

Gosub init_sprites

Repeat ; Main Loop
  
  If WaitWindowEvent(1)=#PB_Event_CloseWindow : End : EndIf
  
  If timer_event_1 ; Wait for Timer
    timer_event_1=0
    FlipBuffers() : ClearScreen(0)
    StartDrawing(ScreenOutput())
    DrawText(4,16,Str(count))
    StopDrawing()
    
    For i=5 To max_balls_1-15 Step 15 : DisplaySprite(#ball,i,7) : Next i ; Show available Ball´s
    
    clinker_1=0
    For ii=0 To clinker Step 30
      For i=4 To win_x Step 40
        ExamineMouse()
        mouse_x=MouseX()-racket_width>>1            ; - a half Racket width
        
        DisplaySprite(#ball,ball_x,ball_y)          ; Show Ball
              
        DisplaySprite(#black_racket,mouse_x+5,win_y-23) ; Show black Background Racket 
        
        If racket_moving
          DisplaySprite(#racket_1,mouse_x,win_y-30) ; Show Racket 1 - Racket is moving
        Else
          DisplaySprite(#racket_0,mouse_x,win_y-30) ; Show Racket 0 - Racket standing still
        EndIf   
        
        If SpriteCollision(#racket_0,Mouse_x,win_y-30,#ball,ball_x,ball_y) ; Racket to Ball Collision
          play_sound(0) ; "Beep" Sound 0
          go_y=-stepp
          If racket_moving ; Racket is moving
            Select racket_moving
              Case 1 ; Racket moves to right
                If ball_x-mouse_x>racket_width>>1
                  go_x=stepp
                Else
                  go_x=stepp>>1
                EndIf
              Case -1 ; Racket moves to left
                If ball_x-mouse_x>racket_width>>1
                  go_x=-stepp>>1
                Else
                  go_x=-stepp
                EndIf
            EndSelect
          Else ; Racket is not moving
            If ball_x-mouse_x>-6 And ball_x-mouse_x<6 ; Racket Edge left Collision
              go_x=-stepp
            ElseIf ball_x-mouse_x>racket_width-6 And ball_x-mouse_x<racket_width ; Racket Edge right Collision
              go_x=stepp
            EndIf
          EndIf
        EndIf
        
        If SpriteCollision(iii,i,50+ii,#ball,ball_x,ball_y) ; --- Collision Clinker´s -----
          If clinker(iii,0)
            go_y=-go_y
            play_sound(2) ; "Beep" Sound 2
            StartDrawing(SpriteOutput(iii))
            Select Point(0,8)
              Case $7F00   : count+1
              Case $7F7F   : count+2
              Case $7F5F00 : count+3
              Case $7F     : count+4
            EndSelect
            StopDrawing()
          EndIf
          
          If ball_x-i<17 ; 16 = a half Clinker width
            RotateSprite(iii,-10,#PB_Relative) : clinker(iii,1)-10
          Else
            RotateSprite(iii,10,#PB_Relative) : clinker(iii,1)+10
          EndIf
          
          If Abs(clinker(iii,1))>30 ; Tilting Angle max
            clinker(iii,0)=0
          Else
            Select Abs(clinker(iii,1)) ; Re coloring Clinker´s
              Case 10 : coloring_clinker(iii,$FFFF)
              Case 20 : coloring_clinker(iii,$FFBF00)
              Case 30 : coloring_clinker(iii,$FF)
              Default : coloring_clinker(iii,$FF00)
            EndSelect
          EndIf
        EndIf ; ------------------------- Collision Clinker´s ----------------------------
        
        If clinker(iii,0) : clinker_1+1 : DisplaySprite(iii,i,50+ii) : EndIf ; Show active Clinker´s
        
        iii+1
      Next i
    Next ii
    
    display_and_rotate_sprite(#rotor_1,win_x>>2-16,20,9)           ; Show Rotor 1
    display_and_rotate_sprite(#rotor_2,win_x>>1-16,20,15)          ; Show Rotor 2
    display_and_rotate_sprite(#rotor_2,win_x>>1-16,20,90)          ; Show Rotor 2
    display_and_rotate_sprite(#rotor_3,win_x/1.3-16,20,-9)         ; Show Rotor 3
    display_and_rotate_sprite(#millstone_left,win_x>>1-32,280,-5)  ; Show Millstone left
    display_and_rotate_sprite(#millstone_right,win_x>>1,280,5)     ; Show Millstone right
    display_and_rotate_sprite(#speedpoint_left,win_x-1000,250,-45) ; Show Speed point left
    display_and_rotate_sprite(#speedpoint_left,win_x-1000,250,-90) ; Show Speed point left
    display_and_rotate_sprite(#speedpoint_right,win_x-232,250,45)  ; Show Speed point right
    display_and_rotate_sprite(#speedpoint_right,win_x-232,250,90)  ; Show Speed point right
    
    collision_rotor(#rotor_1,>>2,3)  ; Collision Rotor 1
    collision_rotor(#rotor_2,>>1,4)  ; Collision Rotor 2
    collision_rotor(#rotor_3,/1.3,3) ; Collision Rotor 3
    
    If SpriteCollision(#millstone_left,win_x>>1-32,280,#ball,ball_x,ball_y)    ; Collision Millstone left
      count+2 : go_x=-stepp : play_sound(2)
    ElseIf SpriteCollision(#millstone_right,win_x>>1,280,#ball,ball_x,ball_y) ; Collision Millstone right
      count+2 : go_x=stepp : play_sound(2)
    EndIf
    
    If (SpriteCollision(#speedpoint_left,win_x-1000,250,#ball,ball_x,ball_y) Or SpriteCollision(#speedpoint_right,win_x-232,250,#ball,ball_x,ball_y)) ; Collision Speed Point´s
      If wait_for_speed_up>50               ; Wait for Speed up
        wait_for_speed_up=0
        If speed_up
          stepp=stepp_old                   ; Speed down to default
        Else
          stepp_old=stepp : stepp+stepp/3   ; Speed up
        EndIf
        If speed_up
          count+4
          coloring_clinker(#speedpoint_left,$FFBF00)  ; Coloring Speed Point 1
          coloring_clinker(#speedpoint_right,$FFBF00) ; Coloring Speed Point 2
        Else
          count+3
          coloring_clinker(#speedpoint_left,$FF)  ; Coloring Speed Point 1
          coloring_clinker(#speedpoint_right,$FF) ; Coloring Speed Point 2
        EndIf
        speed_up=~speed_up
        play_sound(2)
      EndIf
    EndIf
    wait_for_speed_up+1 ; Slowly speed up the Ball
    
    ;If ball_y>win_y : go_y=-go_y : EndIf ; Demo mode for Test´s
    
    If Not clinker_1 Or ball_y>win_y+25; Next Level or exit
      If ball_y>win_y+25 ; Ball is exit
        max_balls_1-15
        If max_balls_1<15 ; Ball´s done
          play_sound(1)   ; "Beep" Sound 1
          StartDrawing(ScreenOutput())
          Box(0,240,win_x,win_y-240,0)  ; Delete Artefakt´s
          DrawingFont(FontID(0))
          DrawText(win_x/2-TextWidth(copyright$)/2,10,copyright$) ; Copyright Text - removing prohibited
          DrawingFont(#PB_Default)
          StopDrawing()
          FlipBuffers()
          ReleaseMouse(1)
          If MessageRequester("Again ?","Score : "+Str(count),#PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
            RunProgram(ProgramFilename())
          EndIf
          End
        EndIf
      EndIf
      
      iii=0 : ball_x=0 : ball_y=ball_y_1 : stepp=0 : speed_up=0
      
      coloring_clinker(#speedpoint_left,$FFBF00)  ; Re coloring Speed Point 1
      coloring_clinker(#speedpoint_right,$FFBF00) ; Re coloring Speed Point 2
      
      If Not clinker_1 ; Next Level, add Speed
        stepp_1+1
        If stepp_1>max_levels
          stepp_1=max_levels
        EndIf
        If speed_up
          stepp=stepp_old
        EndIf
        Gosub init_sprites
      EndIf
    EndIf
    
    If Random(10)>9 ; Breaking the symmetric Ball moving - angry:-)
      ball_x+Random(1) : ball_y+Random(1)
    EndIf
    
    ball_x+go_x : ball_y+go_y
    If ball_x>win_x-6 : go_x=-stepp : EndIf
    If ball_x<0       : go_x=stepp  : EndIf
    If ball_y<0       : go_y=stepp  : EndIf
    
    swapping=~swapping ; --------- Analyse moving Racket -----------
    If swapping : moving_a=mouse_x : Else :moving_b=mouse_x :EndIf
    If moving_a=moving_b
      racket_pos=mouse_x 
      racket_moving=0 ; Racket moves not
    Else
      If mouse_x>racket_pos
        racket_moving=1  ; Racket moves to right
      ElseIf mouse_x<racket_pos
        racket_moving=-1 ; Racket moves to left
      EndIf
    EndIf ; -------------------------------------------------------
    
    If iii>29 : iii=0 : EndIf
    ExamineKeyboard() ; Bye with Escape
    If KeyboardPushed(#PB_Key_Escape)
      End
    EndIf
  EndIf ; Wait for Timer
ForEver ; Repeat the Main Loop

;-------------------- Subroutine init Sprites ----------------------
init_sprites:
play_sound(1) ; "Beep" Sound 1

For i=0 To clinker
  CreateSprite(i,32,16) ; Create Clinker´s
  coloring_clinker(i,$FF00)
  RotateSprite(i,180,#PB_Absolute)
  clinker(i,0)=1 ; Clinker´s on
Next i

CopySprite(0,#rotor_1)                         ; Create Rotor 1
CopySprite(0,#rotor_2)                         ; Create Rotor 2
coloring_clinker(#rotor_1,$FFBF00)             ; Coloring Rotor 1
coloring_clinker(#rotor_2,$FF)                 ; Coloring Rotor 2 
CopySprite(#rotor_1,#rotor_3)                  ; Create Rotor 3 
CreateSprite(#millstone_left,32,16)            ; Create Millstone left
coloring_clinker(#millstone_left,$FFFF)        ; Coloring Millstone left
CopySprite(#millstone_left,#millstone_right)   ; Create Millstone right
CopySprite(#rotor_1,#speedpoint_left)          ; Create Speed Point left
CopySprite(#rotor_1,#speedpoint_right)         ; Create Speed Point right
CreateSprite(#racket_0,racket_width,10)        ; Create Racket 0 - standing still
CreateSprite(#ball,7,7)                        ; Create Ball
CreateSprite(#black_racket,racket_width-10,10) ; Create black Racket - Background for Highspeed
SpriteQuality (#PB_Sprite_BilinearFiltering)   ; Show High Quality Sprites
StartDrawing(SpriteOutput(#ball))              ; Coloring Ball
Circle(3,3,3,-1)
StopDrawing()

StartDrawing(SpriteOutput(#racket_0))          ; Coloring Racket 0
Box(0,0,5,10,$00D7FF)
Box(racket_width-5,0,5,10,$00D7FF)
Box(5,0,racket_width-10,7,-1)
DrawingMode(#PB_2DDrawing_Gradient)
LinearGradient (0,0,0,3)
Box(5,4,racket_width-10,4)
FrontColor($00D7FF)
Box(5,4,racket_width-10,4)
StopDrawing()

CopySprite(#racket_0,#racket_1)               ; Create Racket 1 - moving

StartDrawing(SpriteOutput(#racket_1))         ; Re-coloring Racket 1 Edges for moving Racket
Box(0,0,5,10,$45FF)
Box(racket_width-5,0,5,10,$45FF)
StopDrawing()

ExamineMouse()
MouseLocate(win_x/2,win_y/2)                  ; Set Racket to Start Point
Return
Last edited by walbus on Mon Apr 24, 2017 8:29 am, edited 1 time in total.
T4r4ntul4
Enthusiast
Enthusiast
Posts: 118
Joined: Tue Mar 04, 2014 4:15 pm
Location: Netherlands

Re: How to use sprites+canvas on the same time? Like Linerid

Post by T4r4ntul4 »

@netmaestro

(For some weird reason my antivirus wont let me execute that code, with or without debugger. It puts it right away in quarantaine, and after that i get an polink error. i use Avira, i think i need a different antivirus (any suggestions?) turned of realtime protection. now it works.)

ontopic:

automation of sprite collision is what i need, so i guess i will go sprites all the way.
i dont need vector graphics.

Your code is a starting point for my project. Thanks for your information so i could make the right decision!


@walbus

Thanks for your code, i will learn alot from that.
Post Reply