'Based on the game Legend of Pandora.
Import mojo
Global tilewidth:Int=10
Global tileheight:Int=10
Class map
Field tilewidth:Float
Field tileheight:Float
Field mapwidth:Int
Field mapheight:Int
Field screenwidth:Int
Field screenheight:Int
Field map:Int[][]
Method New( screenwidth:Int,
screenheight:Int,
mapwidth:Int,
mapheight:Int)
Self.screenwidth = screenwidth
Self.screenheight = screenheight
Self.mapwidth = mapwidth
Self.mapheight = mapheight
Self.tilewidth = Float(screenwidth)/Float(mapwidth)
Self.tileheight = Float(screenheight)/Float(mapheight)
map = New Int[mapwidth][]
For Local i=0 Until mapwidth
map[i] = New Int[mapheight]
Next
map[mapwidth/2][mapheight/2] = 3 ' 3 is a door
makemap
End Method
Method makemap()
Local timeout:Int
While timeout<(mapwidth*mapheight)*20
timeout+=1
Local x:Int=Rnd(11,mapwidth-11)
Local y:Int=Rnd(11,mapheight-11)
If map[x][y] = 3
makeroom(x,y)
End If
Wend
'here we turn doors into walls
'if they should be walls
For Local y1=1 Until mapheight-1
For Local x1=1 Until mapwidth-1
If map[x1][y1] = 3
Local cnt:Int=0
For Local y2=y1-1 To y1+1
For Local x2=x1-1 To x1+1
If map[x2][y2] = 2 Then cnt+=1
Next
Next
If cnt>3 Then map[x1][y1] = 2
End If
Next
Next
'here we turn doors into walls if they
' touch tiles that are nothing (0)
For Local y1=1 Until mapheight-1
For Local x1=1 Until mapwidth-1
If map[x1][y1] = 3
Local cnt:Int=0
For Local y2=y1-1 To y1+1
For Local x2=x1-1 To x1+1
If map[x2][y2] = 0 Then cnt+=1
Next
Next
If cnt>0 Then map[x1][y1] = 2
End If
Next
Next
'here we turn the doors into floors
For Local y1=0 Until mapheight
For Local x1=0 Until mapwidth
If map[x1][y1] = 3 Then map[x1][y1] = 1
Next
Next
End Method
Method makeroom(x:Int,y:Int)
Local side:String
If map[x][y-1] = 0
side="up"
Elseif map[x+1][y] = 0
side="right"
Elseif map[x][y+1] = 0
side="down"
Elseif map[x-1][y] = 0
side="left"
End If
Local w:Int=Rnd(5,10)
Local h:Int=Rnd(5,10)
If side="up"
Local x1:Int=x-w/2
Local y1:Int=y-h
If roomfits(x1,y1,w,h)
insertroom(x1,y1,w,h+1)
'door up
map[x1+Rnd(2,w-2)][y1] = 3
' door right
map[x1+w-1][y1+Rnd(2,h-2)] = 3
'door left
map[x1][y1+Rnd(2,h-2)] = 3
End If
End If
If side="right"
Local x1:Int=x+1
Local y1:Int=y-h/2
If roomfits(x1,y1,w,h)
insertroom(x1-1,y1,w,h)
'door up
map[x1+Rnd(2,w-2)][y1] = 3
'door down
map[x1+Rnd(2,w-2)][y1+h-1] = 3
' door right
map[x1+w-2][y1+Rnd(2,h-2)] = 3
End If
End If
If side="left"
Local x1:Int=x-w
Local y1:Int=y-h/2
If roomfits(x1,y1,w,h)
insertroom(x1,y1,w+1,h)
'door up
map[x1+Rnd(2,w-2)][y1] = 3
'door down
map[x1+Rnd(2,w-2)][y1+h-1] = 3
'door left
map[x1][y1+Rnd(2,h-2)] = 3
End If
End If
If side="down"
Local x1:Int=x-w/2
Local y1:Int=y+1
If roomfits(x1,y1,w,h)
insertroom(x1,y1-1,w,h)
'door down
map[x1+Rnd(2,w-2)][y1+h-2] = 3
'door left
map[x1][y1+Rnd(2,h-2)] = 3
' door right
map[x1+w-1][y1+Rnd(2,h-2)] = 3
End If
End If
End Method
Method insertroom(x,y,w,h)
For Local y2=y Until y+h
For Local x2=x Until x+w
If map[x2][y2] <> 3 Then map[x2][y2] = 2
Next
Next
For Local y2=y+1 Until y+h-1
For Local x2=x+1 Until x+w-1
map[x2][y2] = 1
Next
Next
End Method
Method roomfits(x:Int,y:Int,w:Int,h:Int)
For Local y1=y Until y+h
For Local x1=x Until x+w
If map[x1][y1] = 1 Then Return False
Next
Next
Return True
End Method
Method draw()
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
Select map[x][y]
Case 0
Case 1'floor
SetColor 100,100,100
DrawRect x*tilewidth,
y*tileheight,
tilewidth+1,
tileheight+1
Case 2'wall
SetColor 200,200,200
DrawRect x*tilewidth,
y*tileheight,
tilewidth+1,
tileheight+1
Case 3'wall
SetColor 244,244,0
DrawRect x*tilewidth,
y*tileheight,
tilewidth+1,
tileheight+1
End Select
Next
Next
End Method
End Class
Class enemy
Field x:Float,y:Float
Field ms:Float 'movement speed
Field w:Int=mymap.tilewidth-8
Field h:Int=mymap.tileheight-8
Field hp:Int
Field hpceil:Int
Field direction:String="up" ' left/right/up/down
Field current:Bool=False 'if being updated
Field deleteme:Bool=False
Method New()
' find a spot to place the new enemy
Local exitloop:Bool=False
Local cnt:Int=0
While exitloop=False
exitloop = True
Local nx = Rnd(50,640-50)
Local ny = Rnd(50,480-50)
Local mx:Int=nx/mymap.tilewidth
Local my:Int=ny/mymap.tileheight
If mymap.map[mx][my] <> 1 Then exitloop = False
For Local i:=Eachin myenemy
If distance(nx,ny,i.x,i.y) < 30 Or distance(myplayer.x,myplayer.y,nx,ny) < 250-cnt
exitloop = False
End If
Next
If exitloop = True Then
x = nx
y = ny
End If
cnt+=1
Wend
' Here we set the movement speed
ms = Rnd(.1,.5)
' Here we set the hitpoints
hp = Rnd(1,50)
' the ceiling is what he has or had at start (powerbar)
hpceil = hp
End Method
Method update()
current=True
' store the old location
Local oldx:Float=x
Local oldy:Float=y
' move the enemy towards the player
If collide(x+1,y) = False And x < myplayer.x Then
x+=ms
direction = "right"
End If
If collide(x-1,y) = False And x > myplayer.x Then
x-=ms
direction = "left"
End If
If collide(x,y+1) = False And y < myplayer.y Then
y+=ms
direction = "down"
End If
If collide(x,y-1) = False And y > myplayer.y Then
y-=ms
direction = "up"
End If
untangle()
current=False
End Method
' if the enemies are inside of each other
' then move them apart
Method untangle()
For Local i:=Eachin myenemy
If i.current=False
If distance(i.x,i.y,x,y) < w
Local a:Int
a = getangle(i.x,i.y,x,y)
Local nx:Float=x
Local ny:Float=y
nx += Cos(a)*1
ny += Sin(a)*1
Local mx:Int=nx/mymap.tilewidth
Local my:Int=ny/mymap.tileheight
If mymap.map[mx][my] = 1
x = nx
y = ny
End If
End If
End If
Next
End Method
Method draw()
SetColor 255,255,0
DrawOval x-w/2,y-w/2,w,w
'powerbar
Local current:Float=(Float(w)/Float(hpceil))*hp
SetColor 0,0,0
DrawRect x-w/2,y+w/2,w,5
SetColor 255,0,0
DrawRect x-w/2,y+1+w/2,current,3
End Method
Method collide:Bool(xx:Int,yy:Int)
For Local i:=Eachin myenemy
If i.current = False
If distance(xx,yy,i.x,i.y) < w Then Return True
End If
Next
Local mx:Int=xx/mymap.tilewidth
Local my:Int=yy/mymap.tileheight
If mymap.map[mx][my] <> 1 Then Return true
Return False
End Method
Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
Return Abs(x2-x1)+Abs(y2-y1)
End Function
Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
Local dx = x2 - x1
Local dy = y2 - y1
Return ATan2(dy,dx)+360 Mod 360
End Function
End Class
Class player
Field x:Float,y:Float
Field w:Int=mymap.tilewidth-8
Field h:Int=mymap.tileheight-8
Field wx:Int,wy:Int
Field direction:String="up" ' up/left/down/right
Field weapondamage:Int=3
Field swing:Bool=False
Field swingcountdown:Int=0
Method New()
Local exitloop:Bool=False
While exitloop = False
x = Rnd(640)
y = Rnd(480)
Local mx:Int=x/mymap.tilewidth
Local my:Int=y/mymap.tileheight
If mymap.map[mx][my] = 1 Then exitloop = True
Wend
direction = "up"
End Method
Method update()
updatecontrols()
weaponenemies()
End Method
Method weaponenemies()
If swing = False Then Return
For Local i:=Eachin myenemy
If distance(i.x,i.y,wx,wy) < w+5
'make sure the weapon does not hit throught
' walls
Local mx:Int=wx/mymap.tilewidth
Local my:Int=wy/mymap.tileheight
If mymap.map[mx][my] <> 1 Then Exit
'distance with the enemy
Local a:Int=getangle(wx,wy ,i.x,i.y)
For Local ww:Int=0 Until w
Local nx:Float=i.x
Local ny:Float=i.y
nx += Cos(a) * 1
ny += Sin(a) * 1
Local mx:Int=nx/mymap.tilewidth
Local my:Int=ny/mymap.tileheight
If mymap.map[mx][my] = 1 Then
i.x = nx
i.y = ny
Else
Exit
End If
Next
i.hp -= weapondamage
If i.hp<1 Then i.deleteme = True
End If
Next
End Method
Method updatecontrols()
' store the location of the player
Local oldx:Int=x
Local oldy:Int=y
'handle the movement
If collide(x+1,y)=False And KeyDown(KEY_RIGHT) Then
x+=1
direction = "right"
swing=False
End If
If collide(x-1,y)=False And KeyDown(KEY_LEFT) Then
x-=1
direction = "left"
swing=False
End If
If collide(x,y-1)=False And KeyDown(KEY_UP) Then
y-=1
direction = "up"
swing=False
End If
If collide(x,y+1)=False And KeyDown(KEY_DOWN) Then
y+=1
direction = "down"
swing=False
End If
'Handle the weapon
If swing = False
If KeyDown(KEY_SPACE) Then
swing=True
If direction = "left" Then wx=x-w ; wy=y
If direction = "right" Then wx=x+w ; wy=y
If direction = "up" Then wx=x ; wy=y-h
If direction = "down" Then wx=x ; wy=y+h
swingcountdown = 20
End If
Else
swingcountdown-=1
If swingcountdown<0 Then swing=False
End If
End Method
' collide with map
Method collide:Bool(xx:Int,yy:Int)
Local mx:Int=xx/mymap.tilewidth
Local my:Int=yy/mymap.tileheight
If mymap.map[mx][my] <> 1 Then Return True
Return False
End Method
Method draw()
SetColor 255,100,0
DrawOval x-w/2,y-w/2,w,w
If swing = True
'where does the swing graphic get drawn
DrawOval wx-w/2,wy-w/2,w,w
End If
End Method
Function getangle:Int(x1:Int,y1:Int,x2:Int,y2:Int)
Local dx = x2 - x1
Local dy = y2 - y1
Return ATan2(dy,dx)+360 Mod 360
End Function
Function distance:Int(x1:Int,y1:Int,x2:Int,y2:Int)
Return Abs(x2-x1)+Abs(y2-y1)
End Function
End Class
Global myplayer:player
Global myenemy:List<enemy> = New List<enemy>
Global mymap:map
Class MyGame Extends App
Method OnCreate()
SetUpdateRate(60)
mymap = New map(640,480,30,30)
myplayer = New player()
'For Local i:=0 Until 10
' myenemy.AddLast(New enemy())
'Next
End Method
Method OnUpdate()
myplayer.update()
' update the enemies
For Local i:=Eachin myenemy
i.update()
Next
' if enemy hitpoint below 1 then remove him from list
For Local i:=Eachin myenemy
If i.deleteme = True Then myenemy.Remove(i)
Next
If myenemy.IsEmpty
Local ms:Int=Rnd(30,36)
mymap = New map(640,480,ms,ms)
myplayer = New player()
Local ecnt:Int=Rnd(2,10)
For Local i:=0 Until ecnt
myenemy.AddLast(New enemy())
Next
End If
End Method
Method OnRender()
Cls 0,0,0
mymap.draw()
For Local i:=Eachin myenemy
i.draw()
Next
myplayer.draw()
SetColor 255,255,255
DrawText "Player vs Monsters on Random map",0,0
DrawText "Space = Weapon , Cursor l/r/u/d = movement",0,20
End Method
End Class
Function Main()
New MyGame()
End Function
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.