game dev challenge (paul doe exercise)

Game development specific discussions.
ron77
Posts: 212
Joined: Feb 21, 2019 19:24

game dev challenge (paul doe exercise)

Post by ron77 »

hi everyone...

paul doe gave me an exercise to create a simple graphic game but with no global variables (no dim shared)

1. "Simple graphic game"
2. No global variables.
3. Solo (high score beating) or multiplayer (leaderboard).
4. Players eat small green boxes
5. Green boxes don't move. Eating one will respawn it at another random location.
6. Black boxes are bad.
7. Black boxes move randomly, bouncing around the screen.
8. Eating green boxes makes the player bigger.
9. Getting hit by a black box kills the player. Score is reset to zero and size
is reset to original size.
10. Boxes cannot escape the screen.
I forgot to mention that black boxes 'bounce' around the screen: their direction is random, but constant and, upon reaching the borders, they just bounce around.

i have started to try and code it and also others that i told them about the exercise said they would like to try and meet the challenge (in the freebasic discored server)

here is a small example of what i cam up with so far (not perfect and with bugs :|

Code: Select all

#Include "fbgfx.bi"
#if __FB_LANG__ = "fb"
Using FB '' Scan code constants are stored in the FB namespace in lang FB
#endif


' Our user defined type.
TYPE ObjectType
     x AS SINGLE
     y AS Single
     x2 As Single
     y2 As Single
     speed AS SINGLE
END TYPE

Dim player1 AS ObjectType
Dim player2 As ObjectType

ScreenRes 800,600 ,8,2,0 ' Sets the graphic mode
SETMOUSE 0,0,0 ' Hides the mouse cursor

player1.x = 40   ' Initial box's position
player1.y = 40
player1.x2 = 30
player1.y2 = 30
player1.speed = 1 ' box's speed => 1 pixel per loop

player2.x = 60
player2.y = 60
player2.x2 = 50
player2.y2 = 50
player2.speed = 1


Sub play(box1 As ObjectType, box2 As ObjectType)
DO

CLS
Line Step(box1.x, box1.y) - Step (box1.x2, box1.y2),15, bf



' According to pushed key we change the box's coordinates.
If MULTIKEY(SC_RIGHT) THEN box1.x = box1.x + box1.speed
If MULTIKEY(SC_LEFT) THEN box1.x = box1.x - box1.speed
IF MULTIKEY(SC_DOWN) THEN box1.y = box1.y + box1.speed
IF MULTIKEY(SC_UP) THEN box1.y = box1.y - box1.speed


Line Step(box2.x, box2.y) - Step (box2.x2, box2.y2), 8, bf


If MULTIKEY(SC_D) THEN box2.x = box2.x + box2.speed
If MULTIKEY(SC_A) THEN box2.x = box2.x - box2.speed
IF MULTIKEY(SC_S) THEN box2.y = box2.y + box2.speed
IF MULTIKEY(SC_W) THEN box2.y = box2.y - box2.speed



ScreenSync

'SCREENLOCK
SLEEP 2         ' Prevents 100% CPU usage
'SCREENUNLOCK

LOOP UNTIL MULTIKEY(SC_Q) OR MULTIKEY(SC_ESCAPE)
End Sub

play(player1, player2)
ron77
Last edited by ron77 on Jul 11, 2020 9:31, edited 1 time in total.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: game dev challenge (paul doe exercise)

Post by BasicCoder2 »

According to jqpabc123 a reason not to use Discord is that your data becomes their data. And there is no way to determine exactly what *your data* includes.
viewtopic.php?t=26784

In your code when I use the arrow keys both "players" move. Maybe something to do with the STEP option in LINE.
Try:
Line (box1.x, box1.y) - Step (box1.x2, box1.y2),15, bf
Line (box2.x, box2.y) - Step (box2.x2, box2.y2), 8, bf
Last edited by BasicCoder2 on Jul 11, 2020 12:39, edited 1 time in total.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: game dev challenge (paul doe exercise)

Post by badidea »

Same code, but different:

Code: Select all

#Include "fbgfx.bi"
#If __fb_lang__ = "fb"
	Using FB '' Scan code constants are stored in the FB namespace in lang FB
#Endif

' Our user defined type.
Type ObjectType
	Dim As Single x, y 'position top/left corner
	Dim As Single w, h 'width and height 
	Dim As Single speed 'in pixels / loop
	Dim As Ulong c 'color (or use ubyte for 8-bit only)
	Declare Constructor(x As Single, y As Single, w As Single, h As Single, speed As Single, c As Ulong)
	Declare Sub Draw()
End Type

Constructor ObjectType(x As Single, y As Single, w As Single, h As Single, speed As Single, c As Ulong)
	this.x = x
	this.y = y
	this.w = w
	this.h = h
	this.speed = speed
	this.c = c
End Constructor

Sub ObjectType.draw()
	Line(x, y)-step(w, h), c, bf
End Sub

Sub play(box1 As ObjectType, box2 As ObjectType)
	Do
		' According to pushed key we change the box's coordinates
		With box1
			If Multikey(SC_RIGHT) Then .x += .speed
			If Multikey(SC_LEFT)  Then .x -= .speed
			If Multikey(SC_DOWN)  Then .y += .speed
			If Multikey(SC_UP)    Then .y -= .speed
		End With

		With box2
			If Multikey(SC_D) Then .x += .speed
			If Multikey(SC_A) Then .x -= .speed
			If Multikey(SC_S) Then .y += .speed
			If Multikey(SC_W) Then .y -= .speed
		End With

		'screensync '(disabled, does not work here)

		Screenlock
		Cls
		box1.draw()
		box2.draw()
		Screenunlock

		Sleep 2         ' Prevents 100% CPU usage

	Loop Until Multikey(SC_Q) Or Multikey(SC_ESCAPE)
End Sub

Dim As ObjectType player1 = ObjectType(40, 40, 30, 30, 1, 15)
Dim As ObjectType player2 = ObjectType(60, 60, 50, 50, 1, 8)

Screenres 800, 600, 8, 2, 0 ' Sets the graphic mode 8-bit, 2 pages
Setmouse 0, 0, 0 ' Hides the mouse cursor

play(player1, player2)
Ignore my comment at screensync, it does seem to work here
ron77
Posts: 212
Joined: Feb 21, 2019 19:24

Re: game dev challenge (paul doe exercise)

Post by ron77 »

hello basicCoder2 and badidea and everyone...

here is the re-work of my code... in this code i try to use arrays of UDT (player(0 to 1) pellets(0 to 11) - they are the green little boxes and i prepared enemey(0 to 5) - as the black boxes

my main problem right now is the pellets now showing on the screen - i tried making then in random positions but no luck (i also use "with" statement)

all i get is the two players :'(

Code: Select all

#Include "fbgfx.bi"

using FB

Randomize Timer

' Our user defined type.
type ObjectType
  x as single
  y as single
  x2 as single
  y2 as single
  speed as single
end type

Type stillObject
	x As Single
	y As Single
	x2 As Single
	y2 As Single
End Type

Dim player(0 To 1) as ObjectType
Dim pellets(0 To 11) As stillObject
Dim enemey(0 To 5) As ObjectType

screenRes(800, 600 ,8, 1, 0) ' Sets the graphic mode
setMouse(0, 0, 0) ' Hides the mouse cursor

with player(0)
  .x = 40   ' Initial box's position
  .y = 40
  .x2 = 10
  .y2 = 10
  .speed = 1 ' box's speed => 1 pixel per loop
end with

with player(1)
  .x = 60
  .y = 60
  .x2 = 10
  .y2 = 10
  .speed = 1
end with

For i As Integer = 0 To 11
	With pellets(i)
		.x = Int(Rnd*790)
		.y = Int(Rnd*590)
		.x2 = 10
		.y2 = 10
	End With
	
Next



sub play(players() As ObjectType, pellets2() As stillobject)
  do
    ' According to pushed key we change the box's coordinates.
    with players(0)
      if(multiKey(SC_RIGHT)) then .x += .speed
      if(multiKey(SC_LEFT)) then .x -= .speed
      if(multiKey(SC_DOWN)) then .y += .speed
      if(multiKey(SC_UP)) then .y -= .speed
    end with
    
    with players(1)
      if(multiKey(SC_D)) then .x += .speed
      if(multiKey(SC_A)) then .x -= .speed
      if(multiKey(SC_S)) then .y += .speed
      if(multiKey(SC_W)) then .y -= .speed
    end with
    
    screenLock() 'Render everything inside screenLock()/screenUnlock()
    cls()
    with players(0)
      line(.x, .y)-(.x + .x2, .y + .y2), 15, bf
    end With
    
    With players(1)
      line(.x, .y)-(.x + .x2, .y + .y2), 8 , bf
    end With
    
    For i As Integer = 0 to 11
    	With pellets2(i)
    		Line(.x, .y)-(.x +.x2, .y +.y2), 12, bf
    	End With
    Next
    
    screenUnlock()
    sleep(2,1) ' Prevent 100% CPU usage. Also, keep sleep outside the screenLock/Unlock...
  loop until(multiKey(SC_Q) ORELSE multiKey(SC_ESCAPE))
end sub

play( player(), pellets())
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: game dev challenge (paul doe exercise)

Post by badidea »

ron77 wrote:all i get is the two players :'(
I don't understand, I do see a bunch of bright red squares here when I run your code.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: game dev challenge (paul doe exercise)

Post by BasicCoder2 »

When I run your code I can see the red "pellets"?

Keep in mind black rectangles will not be seen on a black background.

Personally I would keep to the 32 bit colors for games for later you might want those blocks to be animated images.

Notice how you have to pass more and more objects in every subroutines parameter list? Although Paul Doe's project is to not use globals I personally think that can be a fixation for simple games. See below I have been a naughty boy and have made all the objects global, that is, visible to all the subroutines that use them. update(), display() and play()

Note I have added a default constructor. This assigns a set of default values to all the objects created. You can still use the other constructor by using a parameter list when you create an object with the DIM statement.

Code: Select all

#Include "fbgfx.bi"
#If __fb_lang__ = "fb"
   Using FB '' Scan code constants are stored in the FB namespace in lang FB
#Endif

' Our user defined type.
Type ObjectType
   Dim As Single x, y 'position top/left corner
   Dim As Single w, h 'width and height
   Dim As Single speed 'in pixels / loop
   Dim As Ulong c 'color (or use ubyte for 8-bit only)
   Declare Constructor 'default constructor
   Declare Constructor(x As Single, y As Single, w As Single, h As Single, speed As Single, c As Ulong)
   Declare Sub Draw()
End Type

Constructor ObjectType()
   this.x = 0  'initialise positions in the main program
   this.y = 0 
   this.w = 20
   this.h = 20
   this.speed = 0
   this.c = 14
End Constructor

Constructor ObjectType(x As Single, y As Single, w As Single, h As Single, speed As Single, c As Ulong)
   this.x = x
   this.y = y
   this.w = w
   this.h = h
   this.speed = speed
   this.c = c
End Constructor

Sub ObjectType.draw()
   Line(x, y)-step(w, h), c, bf
End Sub

Dim shared As ObjectType player1 = ObjectType(40, 40, 30, 30, 1, 15)
Dim shared As ObjectType player2 = ObjectType(60, 60, 50, 50, 1, 8)
Dim shared As ObjectType pellets(0 to 11)
Dim shared As ObjectType enemy(0 to 5)

'initialize random directions
for i as integer = 0 to 11
    pellets(i).x = int(rnd(1)*800)
    pellets(i).y = int(rnd(1)*600)
next i
for i as integer = 0 to 5
    enemy(i).x = int(rnd(1)*800)
    enemy(i).y = int(rnd(1)*600)
    enemy(i).c = 5
next i

sub update()
      With player1
         If Multikey(SC_RIGHT) Then .x += .speed
         If Multikey(SC_LEFT)  Then .x -= .speed
         If Multikey(SC_DOWN)  Then .y += .speed
         If Multikey(SC_UP)    Then .y -= .speed
      End With

      With player2
         If Multikey(SC_D) Then .x += .speed
         If Multikey(SC_A) Then .x -= .speed
         If Multikey(SC_S) Then .y += .speed
         If Multikey(SC_W) Then .y -= .speed
      End With
end sub

sub display()
      Screenlock
      Cls
      player1.draw()
      player2.draw()
      for i as integer = 0 to 11
          pellets(i).draw()
      next i
      for i as integer = 0 to 5
          enemy(i).draw()
      next i
      Screenunlock
end sub

Sub play()
   Do
      update()
      display()
      Sleep 2         ' Prevents 100% CPU usage
   Loop Until Multikey(SC_Q) Or Multikey(SC_ESCAPE)
End Sub

Screenres 800, 600, 8, 2, 0 ' Sets the graphic mode 8-bit, 2 pages
Setmouse 0, 0, 0 ' Hides the mouse cursor

play()

paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: game dev challenge (paul doe exercise)

Post by paul doe »

BasicCoder2 wrote:...
Notice how you have to pass more and more objects in every subroutines parameter list? Although Paul Doe's project is to not use globals I personally think that can be a fixation for simple games. See below I have been a naughty boy and have made all the objects global, that is, visible to all the subroutines that use them. update(), display() and play()
...
There are some very, very good reasons for learning not to rely on global variables for anything, and learning how to make data in an app ebb and flow nicely.

So, challenge failed XD
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: game dev challenge (paul doe exercise)

Post by BasicCoder2 »

paul doe wrote:So, challenge failed XD
Oh no another failure to add to my litany of failures!
Although I wrote a complete version of the game I will not post it until others have had a go at it.
This is a display of the game in progress...

Image
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: game dev challenge (paul doe exercise)

Post by fxm »

Sorry not to participate in this challenge.
I have an aversion to everything related to games (to play and to code them).
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: game dev challenge (paul doe exercise)

Post by dodicat »

I quite enjoy trying to code games, but not playing them (especially this)
I follow the rules approximately, with only one killer box (red).
No globals, but cheated by using two byref functions to simulate two globals.
Use the mouse rather than the keyboard, start off with the eater box in the bottom right.
The mouse can be a bit severe, could easily code for the arrows, which would make it a more gentle affair.

Code: Select all

#define difficulty .85 '(1 easy, 0 difficult)
#define Irange(f,l) Int(Rnd*((l+1)-(f)))+(f)
#define incircle(cx,cy,radius,x,y) (cx-x)*(cx-x) +(cy-y)*(cy-y)<= radius*radius

Function Regulate(Byval MyFps As Long,Byref fps As Long=0) As Long
    Static As Double timervalue,_lastsleeptime,t3,frames
    frames+=1
    If (Timer-t3)>=1 Then t3=Timer:fps=frames:frames=0
    Var sleeptime=_lastsleeptime+((1/myfps)-Timer+timervalue)*1000
    If sleeptime<1 Then sleeptime=1
    _lastsleeptime=sleeptime
    timervalue=Timer
    Return sleeptime
End Function

Type box
    As Long x,y
    As Long free
    Declare Static Sub checkfree(() As box)
    Declare Static Function checkclear( As box) As Long
End Type

Sub box.checkfree(b() As box)
    For n As Long=Lbound(b) To Ubound(b)
        If Point(b(n).x+30,b(n).y+30)=Rgb(0,0,0) Then b(n).free=1 Else b(n).free=0
    Next n
End Sub

Function box.checkclear(b As box) As Long
    If Point(b.x,b.y)=Rgb(0,0,0) And Point(b.x+60,b.y)=Rgb(0,0,0) And _
    Point(b.x+60,b.y+60)=Rgb(0,0,0) And Point(b.x,b.y+60)=Rgb(0,0,0)_
    Then 
    Return 1
Else
    Return 0
End If
End Function

Type frame
    As Long x,y
    As Long w,h
    As zstring * 50 caption
    As Any Ptr i
    As Long active
    Declare Sub show()
    Declare Function map(a As Single,b As Single,x As Single,c As Single,d As Single) As Single
    Declare  Function overlapped(() As frame,As Long=0) As Long
    Declare Constructor
    Declare Constructor(W As Long,h As Long,col As Ulong,px As Long,py As Long,As String,As boolean)
    Declare Sub update()
    Declare Sub MoveByMouse(As Long, As Long, As Long,x() As frame,() As box)
    Declare Static Sub showscreen(() As Frame)
    Declare Function InImage(As Long,As Long) As Long
    Declare Static Sub destroy(() As frame)
    Declare Sub Write(As Long,As Long,As String)
    Declare Sub blow(sz As Single,As String="")
End Type

Function killer() Byref As frame
    Static As frame k
    Return k
End Function

Function kl() Byref As Long
    Static As Long k
    Return k
End Function

Constructor frame
If Screenptr=0 Then Print "No graphics screen!":Sleep:End
End Constructor

Constructor frame(Wd As Long,hi As Long,col As Ulong,px As Long,py As Long,cap As String,a As boolean)
If Screenptr=0 Then this.constructor
If i Then Imagedestroy i
i=Imagecreate(wd,hi,col)
x=px:y=py
w=Wd:h=Hi
Var b=(h+w)/4
For k As Single=1 To b\10
    Var z=map(1,b/10,k,1,.1)
    Var r=Cptr(Ubyte Ptr,@col)[2]
    Var g=Cptr(Ubyte Ptr,@col)[1]
    Var b=Cptr(Ubyte Ptr,@col)[0]
    Line i,(k,k)-(w-k,h-k),Rgb(r*z,g*z,b*z),b
Next k
Line i,(b\10,b\10)-(wd-b\10,25),Rgb(0,100,255),bf
Draw String i,(b\10,b\10),cap
If cap="EATER" Then
    Circle i,(wd\2-.2*wd\2,hi/1.75),.02*wd,0,,,,f
    Circle i,(wd\2+.2*wd\2,hi/1.75),.02*wd,0,,,,f
    Circle i,(wd\2,hi/1.6),.25*wd,0
    Circle i,(wd\2,hi/1.6),.15*wd,0,4.5,5.9
End If
caption=cap
active=a
End Constructor

Sub frame.blow(sz As Single,c As String="")
    If c="" Then
        this.constructor(w+sz,h+sz,Rgb(255,255,255),x,y,"EATER",true) 
    Else
        this.constructor(w+sz,h+sz,Rgb(255,255,255),x,y,c,true) 
    End If
End Sub

Sub frame.show()
    Put(x,y),i,Pset
End Sub

Function frame.Overlapped(f() As Frame,flag As Long=0) As Long
    Dim As box p2(1 To 4)
    If flag=0 Then
        For n As Long=Lbound(f) To Ubound(f)-1
            p2(1).x=f(n).x:p2(1).y=f(n).y
            p2(2).x=f(n).x+f(n).w:p2(2).y=f(n).y
            p2(3).x=f(n).x+f(n).w:p2(3).y=f(n).y+f(n).h
            p2(4).x=f(n).x:p2(4).y=f(n).y+f(n).h
            For n2 As Long=1 To 4
                If n<>35 And f(n).active Then
                    If p2(n2).x<x+w And p2(n2).x>x And p2(n2).y<y+h And p2(n2).y>y  Then Return n 
                End If
            Next n2
        Next n
    Else
        p2(1).x=killer.x:p2(1).y=killer.y
        p2(2).x=killer.x+killer.w:p2(2).y=killer.y
        p2(3).x=killer.x+killer.w:p2(3).y=killer.y+killer.h
        p2(4).x=killer.x:p2(4).y=killer.y+killer.h
        For n2 As Long=1 To 4
            If f(Ubound(f)).InImage(p2(n2).x,p2(n2).y) Then 
                f(Ubound(f)).active=false
            End If
        Next n2
    End If
    Return 0
End Function

Function frame.map(a As Single,b As Single,x As Single,c As Single,d As Single) As Single
    Return ((d)-(c))*((x)-(a))/((b)-(a))+(c)
End Function

Sub frame.showscreen(n() As frame)
    Static As Long fps
    Screenlock
    Cls
    Draw String(10,750),"FPS = "&fps
    killer.show
    For m As Long=1 To Ubound(n)
        If n(m).active Then n(m).show
    Next m
    Screenunlock
    Sleep regulate(60,fps)
End Sub

Sub movekiller
    Static As Single dx,dy,start
    If start=0 Then
        dx=(Rnd-Rnd)*10
        dy=(Rnd-Rnd)*10
        start=1
    End If
    killer.x+=dx*kl
    killer.y+=dy*kl
    If killer.x<0 Or killer.x>1024-60 Then dx=-dx
    If killer.y<0 Or killer.y>768-60 Then dy=-dy
End Sub

Function checkdone(f() As frame) As Long
    For n As Long=Lbound(f) To Ubound(f)-1
        If f(n).active Then Return 0
    Next n
    Return 1
End Function

Sub Frame.MoveByMouse(mx As Long,my As Long,button As Long,n() As frame,bx() As box)
    Dim As Long x1=mx,y1=my,dx,dy,b
    Dim As Long idx=x-mx,idy=y-my
    Dim As Long ov
    While button = 1
        frame.showscreen(n())
        box.checkfree(bx())
        If checkdone(n()) Then this.blow(0,"WINNER"):kl()=0
        Var m=irange(Lbound(bx),(Ubound(bx)-1))
        If m>0 Andalso bx(m).free And Rnd >difficulty Then
            Dim As box ctrf=Type(n(Ubound(n)).x+n(Ubound(n)).w/2,n(Ubound(n)).y+n(Ubound(n)).h/2)
            Dim As box ctrc=Type(bx(m).x+30,bx(m).y+30)
            Var ic=  incircle(ctrf.x,ctrf.y,2*n(Ubound(n)).w,ctrc.x,ctrc.y)
            If ic=0 Then 
                n(m).active=true
            End If
        End If
        
        movekiller
        Type<frame>.overlapped(n(),1)
        box.checkfree(bx())
        Getmouse mx,my,,button
        If mx>0 And my>0 Then
            If mx<>x1 Or my<>y1  Then
                dx = mx-x1
                dy = my-y1
                x1 = mx
                y1 = my
                x=x1+dx+idx
                y=y1+dy+idy
                ov=this.Overlapped(n())
                If ov <>0 Andalso n(ov).active Then 
                    n(ov).active=0
                    this.blow(2)
                    Exit Sub
                End If
            End If
        End If
        
    Wend
End Sub

Function Frame.InImage(mx As Long,my As Long) As Long
    Return  mx<x+w And mx>x And my<y+h And my>y
End Function

Sub frame.destroy(f() As frame)
    Erase f
    Windowtitle "THE END"
End Sub

Sub frame.write(xp As Long=0,yp As Long=0,s As String)
    Draw String i,(xp,yp),s
End Sub


'+++++++++++  START +++++++++++++

Const sz=60
Screen 20,32
Redim As frame f()
Redim  As box bx()
Dim As Long c
For x As Long=10 To 1024-80 Step 150
    For y As Long=10 To 768-80 Step 150
        c+=1
        Redim Preserve bx(1 To c)
        Redim Preserve f(1 To c)
        bx(c).x=x:bx(c).y=y:bx(c).free=0
        Var colour=Rgb(Rnd*150,Rnd*150,Rnd*150)
        f(c)=frame(sz,sz,colour,x,y,"box "+Str(c),true)
    Next
Next

f(Ubound(f)).blow(10)
killer()=frame(sz,sz,Rgb(255,0,0),100,100,"KILLER",false)

Dim As Long mx,my,mb
kl()=1
dim as string key
Do
    Getmouse mx,my,,mb
    If f(Ubound(f)).InImage(mx,my) Then f(Ubound(f)).MoveByMouse(mx,my,mb,f(),bx())
    movekiller
    Type<frame>.overlapped(f(),1)
    frame.showscreen(f())
    
    If checkdone(f()) Then f(Ubound(f)).blow(0,"WINNER"):kl()=0
    key=inkey
Loop Until key=chr(27) or key=chr(255)+"k" 'close button

frame.destroy(f())


 
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: game dev challenge (paul doe exercise)

Post by BasicCoder2 »

dodicat wrote:I quite enjoy trying to code games, but not playing them (especially this)
Yes I never play computer games, too many other interesting things to do including some other coding and hardware projects.
Wonder if Paul Doe will give you a pass :)
Last edited by BasicCoder2 on Jul 14, 2020 5:03, edited 1 time in total.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: game dev challenge (paul doe exercise)

Post by paul doe »

BasicCoder2 wrote:...
Wonder if Paul Doe will give you a pass :)
ron77 wrote:...
10. Boxes cannot escape the screen.
When playing it, I made a sudden move and then the player frame dissapeared from the play area, leaving me with empty feelings as I had lost sight of that snide smile...

@dodicat: quite nice. It does not follow the rules, but it's nice nonetheless XD

The entire point of this 'exercise' is to create a simple application (a game), based on a specification. The requirements will change later (such as, adding music/sound, a menu, saving and loading states, and many more). The overall idea is that the code resists such changes in the specification with the minimal amount of fuss, and to be able to reuse code aggressively if possible. Never solve a problem twice, especially nasty ones.
Last edited by paul doe on Jul 13, 2020 1:21, edited 4 times in total.
alpha2020ca
Posts: 1
Joined: Jul 13, 2020 0:04

brlapi

Post by alpha2020ca »

Hi!
I'm blind and I want develop a game engine for the blind and i choose freebasic for the portability because there's one call blastbay game toolkit(BGT) but it's only for windows I need some help to make a .bi for the libbrlapi from the project brltty to make possibility to control braille displays. And for the nvdacontrollerclient32.dll for the windows operatiog system using the screen reader nvda. Someone can help me?
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: game dev challenge (paul doe exercise)

Post by paul doe »

This is a 'template' that only implements minimal game logic, but it illustrates the idea:

Code: Select all

function _
  rangeRnd overload( _
    byval aMin as integer, _
    byval aMax as integer ) _
  as integer
  
  return( int( rnd() * ( ( aMax + 1 ) - aMin ) + aMin ) )
end function

function _
  rangeRnd( _
    byval aMin as double, _
    byval aMax as double ) _
  as double
  
  return( rnd() * ( aMax - aMin ) + aMin )
end function

type _
  Bounds
  
  as integer _
    top, left, right, bottom
end type

type _
  Player
  
  as single _
    x, y, _
    speed
end type

type _
  Enemy
  
  as single _
    x, y, _
    dx, dy, _
    speed
end type

type _
  Pellet
  
  as single _
    x, y
end type

type _
  GameState
  
  declare constructor()
  declare constructor( _
    byval as integer, _
    byval as integer, _
    byval as integer )
  declare destructor()
  
  as Bounds bound
  
  as Player players( any )
  as Enemy enemies( any )
  as Pellet pellets( any )
  
  as integer playerCount
  as integer enemyCount
  as integer pelletCount
end type

constructor _
  GameState()
  
  constructor( 1, 10, 100 )
end constructor

constructor _ 
  GameState( _
    byval numPlayers as integer, _
    byval numEnemies as integer, _
    byval numPellets as integer )
  
  playerCount => numPlayers
  enemyCount => numEnemies
  pelletCount => numPellets
  
  redim players( 0 to playerCount - 1 )
  redim enemies( 0 to enemyCount - 1 )
  redim pellets( 0 to pelletCount - 1 )
end constructor

destructor _
  GameState()
end destructor

sub _
  update( _
    byref state as GameState )
  
  '' Update enemies
  for _
    i as integer => 0 _
    to state.enemyCount - 1
    
    with state.enemies( i )
      .x +=> .dx * .speed
      .y +=> .dy * .speed
      
      if( .x < state.bound.left ) then
        .x => 0
        .dx => -.dx
      end if
      
      if( .x > state.bound.right ) then
        .x => state.bound.right
        .dx => -.dx
      end if
      
      if( .y < state.bound.top ) then
        .y => state.bound.top
        .dy => -.dy
      end if
      
      if( .y > state.bound.bottom ) then
        .y => state.bound.bottom
        .dy => -.dy
      end if
    end with
  next
end sub

sub _
  render( _
    byref state as GameState )
  
  '' Render enemies
  for _
    i as integer => 0 _
    to state.enemyCount - 1
    
    with state.enemies( i )
      line _
        ( .x - 5, .y - 5 ) - _
        ( .x + 5, .y + 5 ), _
        rgba( 255, 255, 255, 255 ), bf
    end with
  next
end sub

/'
  Main code
'/
var _
  state => GameState( 1, 10, 100 )

with state
  .bound => type <Bounds>( 0, 0, 800, 600 )
  
  '' Create some enemies
  for _
    i as integer => 0 to _
    .enemyCount - 1
    
    .enemies( i ) => type <Enemy>( _
      rangeRnd( 0, .bound.right ), rangeRnd( 0, .bound.bottom ), _
      rangeRnd( -1.0, 1.0 ), rangeRnd( -1.0, 1.0 ), _
      rangeRnd( 1.0, 3.0 ) )
  next
end with

'' Init screen
screenRes( _
  state.bound.right, _
  state.bound.bottom, 32 )

'' Main loop
do
  update( state )
  
  screenLock()
    cls()
    
    render( state )
  screenUnlock()
  
  sleep( 1, 1 )
loop until( len( inkey() ) )
It just satisfies one of the points of the specification (enemies bouncing around the screen). The rest can be easily worked out from here.
ron77
Posts: 212
Joined: Feb 21, 2019 19:24

Re: game dev challenge (paul doe exercise)

Post by ron77 »

hello badidea basicCoder2 paul doe fxm and everyone...

here is my solution to the game exercise based on paul doe 'template' :
please tell me if you find bugs...

p.s. last edit fixed players borders size with screen boundaries
p.s. - last last edit added BEEP sound effect when players eat pellets or get hit by black boxes
p.s. - final edit - added score for each player

Code: Select all

#Include "fbgfx.bi"

using FB






/' Commonly used colors '/
enum Colors
  Background => rgba( 240, 240, 240, 255 )
  Pellet     => rgba( 46, 204, 113, 255 )
  Enemy      => rgba( 44, 62, 80, 255 )
  Player1    => RGBA( 255, 0, 0, 255 )
  Player2    => rgba( 0, 0, 255, 255 )
end Enum


function _
  rangeRnd overload( _
    byval aMin as integer, _
    byval aMax as integer ) _
  as integer
  
  return( int( rnd() * ( ( aMax + 1 ) - aMin ) + aMin ) )
end function

function _
  rangeRnd( _
    byval aMin as double, _
    byval aMax as double ) _
  as double
  
  return( rnd() * ( aMax - aMin ) + aMin )
end function

type _
  Bounds
  
  as integer _
    top, left, right, bottom
end type

type _
  Player
  
  as single _
    x, y, _
    speed, _
    size, _
    points
end type

type _
  Enemy
  
  as single _
    x, y, _
    dx, dy, _
    speed
end type

type _
  Pellet
  
  as single _
    x, y
end type

type _
  GameState
  
  declare constructor()
  declare constructor( _
    byval as integer, _
    byval as integer, _
    byval as integer )
  declare destructor()
  
  as Bounds bound
  as Player players( any )
  as Enemy enemies( any )
  as Pellet pellets( any )
  
  
  
  as integer playerCount
  as integer enemyCount
  as integer pelletCount
end type

constructor _
  GameState()
  
  this.constructor( 2, 10, 100 )
end constructor

constructor _ 
  GameState( _
    byval numPlayers as integer, _
    byval numEnemies as integer, _
    byval numPellets as integer )
  
  playerCount => numPlayers
  enemyCount => numEnemies
  pelletCount => numPellets
  
  redim players( 0 to playerCount - 1 )
  redim enemies( 0 to enemyCount - 1 )
  redim pellets( 0 to pelletCount - 1 )
end constructor

destructor _
  GameState()
end destructor

sub _
  update( _
    byref state as GameState )
  
  for _
    i as integer => 0 to state.enemyCount - 1
    
    with state.enemies( i )
      .x +=> .dx * .speed
      .y +=> .dy * .speed
      
      if( .x < state.bound.left ) then
        .x => 0
        .dx => -.dx
      end if
      
      if( .x > state.bound.right ) then
        .x => state.bound.right
        .dx => -.dx
      end if
      
      if( .y < state.bound.top ) then
        .y => state.bound.top
        .dy => -.dy
      end if
      
      if( .y > state.bound.bottom ) then
        .y => state.bound.bottom
        .dy => -.dy
      end if
    end with
  Next
  For i As Integer => 0 To state.playercount - 1
	With state.players(i)
 		 .speed => 1 
 		 if( .x - .size < state.bound.left ) then
        .x = .x + 1
        
      end if
      
      if( .x + .size > state.bound.right ) then
        .x = .x - 1
        
      end if
      
      if( .y - .size< state.bound.top ) then
        .y = .y + 1
      end if
      
      if( .y +.size > state.bound.bottom ) then
        .y = .y - 1
      end If   
	End With
  Next
  
  
  
  
end sub

sub _
  render( _
    byref state as GameState )
  'var playcolor(0 To 1) => {colors.player1, colors.player2} 
  for _
    i as integer => 0 to state.enemyCount - 1
    
    with state.enemies( i )
      line _
        ( .x - 5, .y - 5 ) - _
        ( .x + 5, .y + 5 ), _
        colors.enemy, bf
    end with
  next
	For i As Integer = 0 To state.playercount - 1
	With state.players(i)
		Line (.x  - .size, .y  - .size) - (.x  + .size, .y  +.size), colors.player1, bf
	End With
	Next
	
	For i As Integer => 0 To state.pelletCount - 1
		With state.pellets(i)
			Line ( .x - 5, .y - 5) - ( .x + 5 , .y + 5), colors.pellet, bf 
		End With
	Next
	
end sub

var _
  b => type <Bounds>( 0, 0, 800, 600 )




screenRes( b.right, b.bottom, 32 )
color( Colors.Enemy, Colors.Background )

var _
  state => GameState()

with state
  .bound => b
  
  for _
    i as integer => 0 to .enemyCount - 1
    
    .enemies( i ) => type <Enemy>( _
      rangeRnd( 0, .bound.right ), rangeRnd( 0, .bound.bottom ), _
      rangeRnd( -1.0, 1.0 ), rangeRnd( -1.0, 1.0 ), _
      rangeRnd( 1.0, 3.0 ) )
  next
end With

For i As Integer => 0 To state.pelletcount - 1
  	With state.pellets(i)
  		.x = Int(Rnd*790)
  		.y = Int(Rnd*590)
  	End With
Next

For i As Integer => 0 To state.playercount - 1
	With state.players(i)
		.x = int(rnd*790)
		.y = int(rnd*590)
		.size = 5
		.points = 0
	End With
Next

do
  update( state )
  
   
  
  With state.players(0)
 		If(multiKey(SC_RIGHT)) then .x += .speed
   	If(multiKey(SC_LEFT)) then .x -= .speed
      if(multiKey(SC_DOWN)) then .y += .speed
      if(multiKey(SC_UP)) then .y -= .speed
      
	End With
  
  with state.players(1)
      if(multiKey(SC_D)) then .x += .speed
      if(multiKey(SC_A)) then .x -= .speed
      if(multiKey(SC_S)) then .y += .speed
      if(multiKey(SC_W)) then .y -= .speed
    end With
  
  
  For x As Integer = 0 To state.playercount - 1
  With state.players(x)
  For i As Integer => 0 To state.pelletcount - 1
  	With state.pellets(i)
  		If (state.players(x).x - state.players(x).size <= state.pellets(i).x +5 and _
  			state.players(x).x + state.players(x).size >= state.pellets(i).x - 5 And _
  			state.players(x).y - state.players(x).size <= state.pellets(i).y + 5 And _
  			state.players(x).y + state.players(x).size >= state.pellets(i).y - 5) Then
  			state.pellets(i).x = (Rnd*790)
  			state.pellets(i).y = (Rnd*590)
  			state.players(x).size += 5
  			state.players(x).points += 1
  			Beep
  		EndIf
  	End With
  Next
  End With
  Next
  
  For x As Integer = 0 To state.playercount - 1
  With state.players(x)
  For i As Integer => 0 To state.enemycount - 1
  	With state.enemies(i)
  		If (state.players(x).x - state.players(x).size <= state.enemies(i).x +5 and _
  			state.players(x).x + state.players(x).size >= state.enemies(i).x - 5 And _
  			state.players(x).y - state.players(x).size <= state.enemies(i).y + 5 And _
  			state.players(x).y + state.players(x).size >= state.enemies(i).y - 5) Then
  			state.players(x).x = (Rnd*790)
  			state.players(x).y = (Rnd*590)
  			state.players(x).size = 5
  			state.players(x).points = 0
  			Beep
  		EndIf
  	End With
  Next
  End With
  Next
  
  
  
  
  screenLock()
    cls()
    
   For i As Integer = 0 To state.playercount - 1
  With state.players(i)
  	Print "player " & Str(i + 1) & " points: " & Str(state.players(i).points)
  End With
  Next 
    
 
    render( state )
  screenUnlock()
  
  sleep( 1, 1 )
loop until( MultiKey(SC_ESCAPE ) )
Post Reply