OOP for Game programs?

Game development specific discussions.
Post Reply
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

OOP for Game programs?

Post by BasicCoder2 »

MrSwiss wrote in thread,
viewtopic.php?f=15&p=243529#p243529
"Note: I don't fancy, the use of "shared" var's., unless absolutely required."

Although I haven't written many OO programs it seems to me that a programmer should at least know how to do OOP and as far as I know it helps remove shared variables?

This is an attempt at a "particle" object. However I am unsure as to how to implement new to create particles when say the left mouse button is down and delete particles when they have "lived" a certain length of time or some other end of life event occurs?

Code: Select all

const SCRW = 640
const SCRH = 480
const MAXP = 100  'number of particles

screenres SCRW,SCRH,32
color rgb(0,0,0),rgb(255,255,255):cls

type PARTICLE
  Public:
  as integer x
  as integer y
  as integer xd
  as integer yd
  as ulong   c
  as integer alive
  Public:
  declare sub drawParticle()
  declare sub moveParticle()
  Declare Constructor()
  Declare Constructor(x As Integer, y As Integer, xd as integer, yd as integer, c As ulong)
end type

sub PARTICLE.drawParticle()
   if this.alive > 0 then
      circle (this.x,this.y),3,this.c,,,,f
   end if
end sub

sub PARTICLE.moveParticle()
   this.x = this.x + this.xd
   this.y = this.y + this.yd
'   if this.x < 0 or this.x > SCRW then this.xd = -this.xd
'   if this.y < 0 or this.y > SCRH then this.yd = -this.yd
   if this.x < 0 or this.x > SCRW then this.alive = 0
   if this.y < 0 or this.y > SCRH then this.alive = 0
end sub

Constructor PARTICLE ()
End Constructor

Constructor PARTICLE (xx As Integer, yy As Integer, xd as integer, yd as integer, cc As ulong)
    this.x = xx
    this.y = yy
    this.xd = xd
    this.yd = yd
    this.c = cc
    this.alive = 255
End Constructor

dim shared as PARTICLE p(1 to MAXP)  'create particle array list
'initialize values
for i as integer = 1 to MAXP
   p(i) = Particle( int(rnd(1)*SCRW), int(rnd(1)*SCRH), int(rnd(1)*3)-1, int(rnd(1)*3)-1,_
          rgb( int(rnd(1)*256), int(rnd(1)*256), int(rnd(1)*256) ) )
next i

sub update()
  screenlock
  cls
  for i as integer = 1 to MAXP
     p(i).drawParticle
     p(i).moveParticle
  next i
  screenunlock
end sub

do
   update()
   sleep 2
loop until multikey(&H01)
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: OOP for Game programs?

Post by Imortis »

New and Delete work with pointers, so you will need to have an array of pointers. In your update loop, you will want to check the alive member, then if it is 0, Delete that item and set it's value to 0. Then when doing the draw/move functions you will want to check first if the item in the array is 0, and only perform the operations if it is not.

That is also helpful with re-populating the array when you click the mouse button, because you can look for items with a value of 0, then fill those with the new particle.

If you need a more in-depth description, or examples, let me know. I would be happy to provide them.

EDIT:
I decided to tweak your code and do it just for giggles.

Code: Select all

const SCRW = 640
const SCRH = 480
const MAXP = 100  'number of particles

screenres SCRW,SCRH,32
color rgb(0,0,0),rgb(255,255,255):cls

type PARTICLE
  Public:
  as integer x
  as integer y
  as integer xd
  as integer yd
  as ulong   c
  as integer alive
  Public:
  declare sub drawParticle()
  declare sub moveParticle()
  Declare Constructor()
  Declare Constructor(x As Integer, y As Integer, xd as integer, yd as integer, c As ulong)
end type

sub PARTICLE.drawParticle()
   if this.alive > 0 then
      circle (this.x,this.y),3,this.c,,,,f
   end if
end sub

sub PARTICLE.moveParticle()
   this.x = this.x + this.xd
   this.y = this.y + this.yd
'   if this.x < 0 or this.x > SCRW then this.xd = -this.xd
'   if this.y < 0 or this.y > SCRH then this.yd = -this.yd
   if this.x < 0 or this.x > SCRW then this.alive = 0
   if this.y < 0 or this.y > SCRH then this.alive = 0
   if this.alive <> 0 then this.alive -= 1
end sub

Constructor PARTICLE ()
End Constructor

Constructor PARTICLE (xx As Integer, yy As Integer, xd as integer, yd as integer, cc As ulong)
    this.x = xx
    this.y = yy
    this.xd = xd
    this.yd = yd
    this.c = cc
    this.alive = 255
End Constructor

dim shared as PARTICLE ptr p(1 to MAXP)  'create particle array list
'initialize values
for i as integer = 1 to MAXP
   p(i) = new Particle( int(rnd(1)*SCRW), int(rnd(1)*SCRH), int(rnd(1)*3)-1, int(rnd(1)*3)-1,_
          rgb( int(rnd(1)*256), int(rnd(1)*256), int(rnd(1)*256) ) )
next i

sub update()
	screenlock
	cls
	for i as integer = 1 to MAXP
		if p(i) <> 0 then
			p(i)->drawParticle
			p(i)->moveParticle
			if p(i)->alive = 0 then
				delete (p(i))
				p(i) = 0
			end if
		end if
	next i
	screenunlock
end sub

dim as integer x,y,wheel,button
do
	getmouse(x,y,wheel,button)
	if button = 1 then
		for i as integer = 1 to MAXP
			if p(i) = 0 then
				p(i) = new Particle( x, y, int(rnd(1)*3)-1, int(rnd(1)*3)-1,_
					rgb( int(rnd(1)*256), int(rnd(1)*256), int(rnd(1)*256) ) )
				exit for
			end if
		next
	end if
	update()
	sleep 2
loop until multikey(&H01)
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: OOP for Game programs?

Post by coderJeff »

@BasicCoder2,

Yea, I was trying to minimize the code I had to post to ask the question I wanted. Here is the actual source, maybe it will give you some ideas. I feel bad though, as it is part of larger system, where everything is an object, but I am not ready to share, yet. Working towards that goal, when I can share the whole thing.

Just links (sorry in advance if they go dead):
gfx_particles.bi
gfx_particles.bas

Uses a "free" and "used" singly linked list to manage the particles. I used to only write for win32, so likely not 64bit friendly, but I am learning.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: OOP for Game programs?

Post by badidea »

Quick hack, not really OOP, can be done much nicer (like above):

Code: Select all

const SCRW = 640
const SCRH = 480
const MAXP = 100  'number of particles

screenres SCRW,SCRH,32
color rgb(0,0,0),rgb(255,255,255):cls

type PARTICLE
	Private:
	as integer x
	as integer y
	as integer xd
	as integer yd
	as ulong   c
	Public:
	as integer alive 'make getter, or move outside PARTICLE...
	Public:
	declare sub drawParticle()
	declare sub moveParticle()
	Declare Constructor()
	Declare Constructor(x As Integer, y As Integer, xd as integer, yd as integer, c As ulong)
end type

sub PARTICLE.drawParticle()
	if alive > 0 then
		circle (x,y),3,c,,,,f
	end if
end sub

sub PARTICLE.moveParticle()
	x += xd
	y += yd
	if x < 0 or x > SCRW then alive = 0
	if y < 0 or y > SCRH then alive = 0
end sub

Constructor PARTICLE ()
End Constructor

Constructor PARTICLE (xx As Integer, yy As Integer, xd as integer, yd as integer, cc As ulong)
	x = xx
	y = yy
	this.xd = xd
	this.yd = yd
	c = cc
	alive = 255
End Constructor

dim shared as PARTICLE p(1 to MAXP)  'create particle array list
	'initialize values
	for i as integer = 1 to MAXP
	p(i) = Particle( int(rnd(1)*SCRW), int(rnd(1)*SCRH), _
		int(rnd(1)*2)*2-1, int(rnd(1)*2)*2-1,_
		rgb( int(rnd(1)*256), int(rnd(1)*256), int(rnd(1)*256) ) )
next i

function add_particle() as integer
	for i as integer = 1 to MAXP
		if p(i).alive = 0 then
			'same stuff again, to be optimised / merged...
			p(i) = Particle( int(rnd(1)*SCRW), int(rnd(1)*SCRH), _
				int(rnd(1)*2)*2-1, int(rnd(1)*2)*2-1,_
				rgb( int(rnd(1)*256), int(rnd(1)*256), int(rnd(1)*256) ) )
				return 0 'ok, added 
		end if
	next
	return -1 'failed to add a particle
end function

sub update_gfx()
	screenlock
	cls
	locate 1,1 : print "press <p> to add particles"
	for i as integer = 1 to MAXP
		p(i).drawParticle
	next i
	screenunlock
end sub

sub update_game()
	for i as integer = 1 to MAXP
		p(i).moveParticle
	next i
end sub

do
	update_game()
	update_gfx()
	if inkey() = "p" then
		add_particle()
	end if
	sleep 2
loop until multikey(&H01)
Some changes:
A) Particle properties Public --> Private
B) update() --> update_gfx() & update_game()
C) xd, yd: int(rnd(1)*3)-1 --> int(rnd(1)*2)*2-1, now all particles move -1 or +1
D) remove 'this.' where possible, just because we can, unlike in python
E) Added 'add_particle()' function
F) 'new' or 'delete' not used
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: OOP for Game programs?

Post by MrSwiss »

A more effective way, to define the PARTICLE type:
(using [U/]Integer in UDT's, is a bad idea since, the size changes,
with the used bitness of the compiler, FBC-32 / FBC-64)

Code: Select all

' a 32-bit random color getter
#Define RndRGB  ( CULng(Rnd() * &hFFFFFF) + &hFF000000ul ) ' full Alpha, always

Const As Short  SCRW = 640, SCRH = 480, MAXP = 100      ' screen size, number of particles
Const As ULong  white = &hFFFFFFFF, black = &hFF000000  ' color definitions

Randomize(Timer, 3)                                     ' seed randomizer
For i As UInteger = 1 To 50                             ' warm up randomizer
    Rnd() : Rnd() : Rnd() : Rnd() : Rnd() : Rnd()
Next

' should be placed before MAIN-LOOP
ScreenRes(SCRW, SCRH, 32, 2)    ' double buffer (use Flip/ScreenCopy, to show)
ScreenSet(1, 0)
Color(black, white) : Cls

Type PARTICLE
  Private:
    As Short    x   ' same size as Integer in -lang "QB", 16-bit
    As Short    y
    As Short    xd
    As Short    yd
    As ULong    c
  Public:
    As Boolean  alive 'make getter, or move outside PARTICLE...
    Declare Sub drawParticle(ByVal radi As Single)  ' size setting of PARTICLE)
    Declare Sub moveParticle()
    Declare Constructor()
    Declare Constructor(ByVal x As Short, ByVal y As Short, ByVal xd as Short, ByVal yd as Short, ByVal c As ULong)
End Type

Sub PARTICLE.drawParticle(ByVal radi As Single)
    If This.alive Then Circle (x, y), radi, c,,,, F ' F = fill
End Sub

' and so on ...
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: OOP for Game programs?

Post by BasicCoder2 »

The reason I didn't make the alive variable a boolean is because in some games it is a measure of health. Hit too many times and the health reduces to death.
Knowing about the requirements to deal with the bitness of a compiler is something that needs to be remembered. I assume an issue in other languages like C++?
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: OOP for Game programs?

Post by MrSwiss »

BasicCoder2 wrote:Knowing about the requirements to deal with the bitness of a compiler is something that needs to be remembered.
I assume an issue in other languages like C++?
Well, I'm not familiar with C++, but in C:
  • Long (C-lang) ..... = Integer (FB-lang), compiler bitness depending
    Int (C-lang) ....... = Long (FB-lang), 32-bit, fixed
    LongLong (C-lang) = LongInt (FB-lang), 64-bit, fixed
Those are the similarities, as far as I know. Applies equally to unsigned types!
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: OOP for Game programs?

Post by dodicat »

My small contribution.

Code: Select all

Const screenw = 1024
Const screenh = 768
Const MAX_PARTICLES = 500
Const Gravity=.01
Screenres screenw,screenh,32

Type V2D
    x As single
    y As single
    dx As single
    dy As single
    As Ulong c
    As boolean active
    Declare Constructor
    Declare Function unit() As V2D 'normalized
End Type

Type Circle 
    As Long x,y,r
    As Ulong c
    As Single a 'aspect ratio
    Declare Constructor
End Type

Constructor Circle
#define range(f,l) (Rnd*((l)-(f))+(f))
r=range(5,30)
x=range((screenw/2),screenw)
y=Rnd*768
c=Rgb(Rnd*255,Rnd*255,Rnd*255)
a=range(.1,3)
End Constructor

Function V2D.unit() As V2D
    Var L=Sqr(x*x+y*y)
    With This
        .x/=L
        .y/=L
    End With
    Return This
End Function

Constructor V2D
c=Rgb(Rnd*255,Rnd*255,Rnd*255)
dx=2+Rnd*2
dy=-Rnd*4
x=-5
y=500
active=1
End Constructor

Sub drawline(x As Long,y As Long,angle As Double,length As Long,col As Ulong)
    Var x2=x+length*Cos(angle)
    Var y2=y-length*Sin(angle)
    Line(x,y)-(x2,y2),col
End Sub

Function Regulate(Byval MyFps As Long,Byref fps As Long) 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

Function incircle(c As Circle,mx As Long,my As Long) As Long
    If (c.a)<=1 Then
        Return(c.a)*((c.x)-(mx))*(c.a)*((c.x)-(mx)) +((c.y)-(my))*((c.y)-(my))<= (c.r)*(c.r)*(c.a)*(c.a)
    Else
        Return(c.a)*((c.x)-(mx))*(c.a)*((c.x)-(mx)) +((c.y)-(my))*((c.y)-(my))<= (c.r)*(c.r)
    End If
End Function

Function inacircle(c() As Circle,p As V2D) As Long
    For n As Long=0 To Ubound(c)
        If incircle(c(n),p.x,p.y) Then Return 1
    Next n
End Function

Sub move(p() As V2D,circ() As Circle, c As Long)
    Dim As V2D tmp,p1
    For n As Long=0 To Iif(c<=MAX_PARTICLES,c,MAX_PARTICLES)
        If p(n).active Then
            p(n).x+=p(n).dx
            p(n).y+=p(n).dy:p(n).dy+=Gravity
        End If
        tmp.x=p(n).dx
        tmp.y=p(n).dy
        tmp=tmp.unit
        Var a1=Atan2(-tmp.y,tmp.x)-2.5
        Var a2=Atan2(-tmp.y,tmp.x)+2.5
        Line( p(n).x, p(n).y ) - Step( -50*tmp.x, -50*tmp.y  ), p(n).c
        drawline(p(n).x,p(n).y,a1,10,p(n).c)
        drawline(p(n).x,p(n).y,a2,10,p(n).c)
        If p(n).y>screenh-2  Or p(n).x> screenw-2 Or inacircle(circ(),p(n))  Then p(n).active=0   
    Next
End Sub

Sub main(p() As V2D,c() As Circle)
    windowtitle "Hastings"
    Dim As Long __,btn,ctr,fps,flag
    Do
        Getmouse __,__,,btn
        If btn=1 And flag=0 Then Redim p(MAX_PARTICLES):Redim c(25):ctr=0:flag=1
        If Rnd>.0001 Then ctr+=1
        Screenlock
        Cls
        Draw String(20,20),"FPS  " &fps
        For n As Long=0 To Ubound(c)
            Circle(c(n).x,c(n).y),c(n).r,c(n).c,,,c(n).a,f
        Next
        move(p(),c(),ctr)
        Screenunlock
        Sleep regulate(60,fps),1
        flag=btn
    Loop Until Len(Inkey)
End Sub

Randomize
Redim As V2D p(MAX_PARTICLES)
Redim As Circle c(25)
main(p(),c())



 
Post Reply