Ok. Sorry to be confusing. What we have are 2 different ways to achieve (almost) the same effect.
These are not necessarily the "right" way, Just "My" way.
1. Spaceship moving with NO OOP, NO Types whatsoever
2. Spaceship Movement with OOP
NO OOP
' 1/5/2005 Bill Radford
' Spaceship Movement tutorial-- "sans OOP"
Strict ' 'strict' = must declare variables
' VARIABLES
Global GW = 640 ' Graphics Height
Global GH = 480 ' Graphics Width
Global GD = 0 ' Graphics Depth "0" means Windowed Mode
Global MID_GH = GH/2 ' Middle of the screen Height (Y)
Global MID_GW = GW/2 ' Middle of the screen width (X)
Global MX,MY ' Used for Mousex() and Mousey()
Graphics(GW,GH,GD) ' set graphics mode
' VARIABLES
Global x# = GW/2 ' SCREEN X and Y POSITION (initially the middle)
Global y# = GH/2
Global xint:Int ' x,y integers fot neater screen printing
Global yint:Int
Global name:String ' string contains the text name of player
Global life = 100 ' life force (defaults to 100)
Global entity ' a placeholder for the image of the actor
Global angle# ' angle# = 0 to 360 degrees
Global velocity# ' speed of the actor (forward momentum?)
Global angular_velocity# ' rotational speed, i.e. how fast it spins
Global angular#,thrust#
Global friction# = 0.99 ' Friction slows down the actor slightly each frame
Global rotfriction# = 0.97 ' slows down the rate of spin slightly each frame
' Create the ship image
entity = CreateImage(64,64,DYNAMICIMAGE)
SetColor 255,255,0
SetLineWidth 3
DrawLine 0,64,32,0
DrawLine 32,0,64,64
DrawOval 24,16,16,16
GrabImage entity,0,0
SetImageHandle(entity,32,48)
' MAIN LOOP
Repeat
Cls ' Clear the screen
' check controls
angular# = 0 ; thrust# = 0 ' RESET to 0 for this frame
' CHECK KEY INPUTS and
If KeyDown(KEY_LEFT) Then angular# = -0.1
If KeyDown(KEY_RIGHT) Then angular# = 0.1
If KeyDown(KEY_UP) Then thrust# = .05
' ADD the key input values to the existing velocities
angular_velocity# = angular_velocity# + angular#
velocity# = velocity# + thrust#
' SUBTRACT the effect of FRICTION from the velocities
angular_velocity# = angular_velocity# * rotfriction#
velocity# = velocity# * friction
' Calculate the direction of travel (angle is 0-360 degrees, the SIN and COS will return a value
' between -1.0 and +1.0
x=x+(velocity*Cos(angle-90))
y=y+(velocity*Sin(angle-90))
' Turn the ship
angle#:+angular_velocity
If angle#<0.0 Then angle#=360.0
If angle#>360.0 Then angle#= 0.00
' If the actor goes off screen, WRAP to other side
If x>GW Then x = 0
If x<0 Then x = GW
If y<0 Then y = GH
If y>GH Then y=0
' show
xint = x ; yint = y
SetRotation(angle) ' turn spaceship to current angle
DrawImage(entity,x,y)
' show text attributes
SetTransform(0,1.1,1.1)
SetColor 0,0,255
DrawRect x-44,y+30,96,15
SetColor 255,255,0
DrawText "x="+xint+" y="+yint,x-40,y+32
DrawText "Velocity = "+velocity,x-40,y+48
Flip ' display the backbuffer (flip to front buffer)
Until KeyHit(KEY_ESCAPE)
OOP inside
[codebox]
Rem
1/3/2005 Bill Radford
Spaceship Movement tutorial-- Version 2 "A Little More OOP"
In this episode I am incorporating some ideas and insights
from fellow BlitzMAXers to make the code a little more OOPy.
Significantly, We added a function called create that will act
as sort of a "Spaceship Object Factory". We also are using a
LINKED LIST to hold our objects.
Thanks to PERTURBIO for the key-binding and check controls methods as
well as other OOP enhancements
End Rem
Strict ' 'strict' = must declare variables
' VARIABLES
Global GW = 800 ' Graphics Height
Global GH = 600 ' Graphics Width
Global GD = 0 ' Graphics Depth "0" means Windowed Mode
Global MID_GH = GH/2 ' Middle of the screen Height (Y)
Global MID_GW = GW/2 ' Middle of the screen width (X)
Global MX,MY ' Used for Mousex() and Mousey()
Global ship_list:Tlist = CreateList() ' create a list to hold our ship objects
Local ship:player
Graphics(GW,GH,GD) ' set graphics mode
Rem
create an actor type that possess attributes that can be used by may different
game characters. Player, enemy, Wizard, etc...
The Type "ACTOR" is the beginning of our Object Oriented Programming (OOP)
Actor is a Class or Type. It simply is a definition of what an "actor" is.
the Fields can also called Attributes. for example, an actor has the x#,y#
Fields that will hold the screen x,y coordinates that tell BMAX where to draw
it. the actor class also has "Methods". Methods are functions that are unique
to that class. the "update" method, for instance, will only work for the actor
class.
End Rem
Type actor
'
Field x# = GW/2 ' SCREEN X and Y POSITION (initially the middle)
Field y# = GH/2
Field xint:Int ' x,y integers fot neater screen printing
Field yint:Int
Field name:String ' string contains the text name of actor
Field life = 100 ' life force (defaults to 100)
Field entity ' a placeholder for the image of the actor
'
Field angle# ' angle# = 0 to 360 degrees
Field velocity# ' speed of the actor (forward momentum?)
Field angular_velocity# ' rotational speed, i.e. how fast it spins
Field friction# = 0.99 ' Friction slows down the actor slightly each frame
Field rotfriction# = 0.97 ' slows down the rate of spin slightly each frame
Method applyImpulse#(angular#,thrust#=0.0)
' add the rotational and/or thrust to the velocities
' these are taken from key inputs. see below
angular_velocity# = angular_velocity# + angular#
velocity# = velocity# + thrust#
End Method
Method update()
Rem
This method calculates the velocity of the ship as well as the
angle. It uses the SINE and COSINE of the current ANGLE to
determine the direction the ship should travel. The ANGLE is between
0 and 360.
both velocities (rotation and forward) are multiplied by a friction
amount that will slow the ship down each frame
End Rem
angular_velocity# = angular_velocity# * rotfriction#
velocity# = velocity# * friction
' move the ship forward
x=x+(velocity*Cos(angle-90))
y=y+(velocity*Sin(angle-90))
' Turn the ship
angle#:+angular_velocity
If angle#<0.0 Then angle#=360.0
If angle#>360.0 Then angle#= 0.00
' If the actor goes off screen, WRAP to other side
If x>GW Then x = 0
If x<0 Then x = GW
If y<0 Then y = GH
If y>GH Then y=0
End Method
Method show()
' This Method is used to draw the current frame of the ship
' as well as the print the x,y and velocity values to the screen
xint = x
yint = y
SetRotation(angle) ' turn spaceship to current angle
DrawImage(entity,x,y)
SetTransform(0,1.1,1.1)
SetColor 0,0,255
DrawRect x-44,y+30,96,15
SetScale 1,1
SetColor 255,255,0
DrawText "x="+xint+" y="+yint,x-40,y+32
DrawText "Velocity = "+velocity,x-40,y+48
End Method
End Type
Rem
Now we create an extended Type called Player. Type Player will INHERIT all of the
attributes and methods of actor, as well as add a new field of its own, inventory.
the [] at the end indicate an array. inventory is an array of strings.
End Rem
Type player Extends actor
Field inventory:String[]
Field _KEYLEFT = KEY_LEFT
Field _KEYRIGHT = KEY_RIGHT
Field _KEYUP = KEY_UP
Field _KEYDOWN = KEY_DOWN
Method SetKey(KeyName:String, KeyVal:Byte)
Select Lower(KeyName)
Case "left"
_KEYLEFT = KeyVal
Case "right"
_KEYRIGHT = KeyVal
Case "up"
_KEYUP = KeyVal
Case "down"
_KEYDOWN = KeyVal
End Select
End Method
Method GetKey(KeyName:String)
Select Lower(KeyName)
Case "left"
Return _KEYLEFT
Case "right"
Return _KEYRIGHT
Case "up"
Return _KEYUP
Case "down"
Return _KEYDOWN
End Select
End Method
Method CheckControls()
If KeyDown(_KEYLEFT) Then applyImpulse(-0.1)
If KeyDown(_KEYRIGHT) Then applyImpulse(0.1)
If KeyDown(_KEYUP) Then applyImpulse(0,0.04)
End Method
Function Destroy(pname$)
Local temp:Player
For temp:player = EachIn ship_list
If temp.name = pname$
Release temp
FlushMem
Return True
endif
next
Return False
End Function
' This is a unique type of function. when called, this function will create a new instance
' of PLAYER. Since functions can be called when there are no existing instances, they can
' be used for this. This adds a nice, tidy way to add new instances of our types, along with
' several attributes (in this case the x,y starting position, name and RGB color)
Function create:player(pname$,pox,poy,red,green,blue)
Local t:player = New player
t.entity = CreateImage(64,64,DYNAMICIMAGE)
t.name = pname
t.x = pox
t.y = poy
SetColor red,green,blue
SetLineWidth 3
DrawLine 0,64,32,0
DrawLine 32,0,64,64
DrawOval 24,16,16,16
SetColor 255,255,0
DrawText pname,32-(Len(pname)*8)/2,20
GrabImage t.entity,0,0
Cls ; Flip
SetImageHandle(t.entity,32,48)
SetScale 1,1
' NEW - we add this INSTANCE of player to the LINKED LIST called ship_list
' so we can iterate through them easily later on
ListAddLast ship_list,t
Return t
End Function
End Type
Type enemy Extends actor
Field anger
End Type
Rem
call the player TYPE's function "create" to create a few instances of type "player"
the we will add them to a LIST
End Rem
' Create INSTANCES of the type player
' This creates the default player
player.create("Bobby",GW-100,GH/2,0,200,0)
' This creates a 2nd player. Since it will have unique keycodes, we will use a temp variable to reference
' it during the KEY binding setup
Global temp:player = player.create("Kate",100,GH/2,200,0,0)
temp.SetKey("left", KEY_A)
temp.SetKey("right", KEY_D)
temp.SetKey("up", KEY_W)
' now we can release the temp variable
Release temp
FlushMem ' Momma says "Always Flush your Memory"
#Main_Loop ' This is an identifier
Repeat
Cls ' Clear the screen
' we now have the player types (the ships) in the Linked List (ship_list)
' we can iterate through them and get control inputs, update their position and
' display them to the screen within a FOR EACHIN loop
For ship:player = EachIn ship_list ' get key inputs to move ship
ship.CheckControls()
ship.update()
ship.show()
Next
If KeyHit(KEY_SPACE)
player.destroy("Kate")
Endif
Flip ' display the backbuffer (flip to front buffer)
Until KeyHit(KEY_ESCAPE)
[/codebox]