Re using Class data across multiple files

Monkey Forums/Monkey Programming/Re using Class data across multiple files

Fryman(Posted 2015) [#1]
I am trying to do some collision detection with a tilemap, I have the project layed out with each main class in its own file so Main.Monkey, Enemys.Monkey, TileMap.Monkey, Player.Monkey Etc

I created the tilemap in Main.Monkey

Field Tiles:TileMap

Tiles = New TileMap



So Tiles exists in Main.Monkey, is there a way for me to use the data from the original Tiles.Monkey instead of me creating a new instance of the class in say Enemys.Monkey and copying it into memory twice?

Sorry if this doesn't make sense, its probably an issue with my coding style rather than monkey, just wanted to see if there is a quick solution rather than me rewriting alot of code.


Fryman(Posted 2015) [#2]
Nevermind got it, was so simple /shame

Global Tiles:TileMap



therevills(Posted 2015) [#3]
Say you have your Tiles variable in a Level class in Main.Monkey:
Main.monkey
Global game:MyGame

Function Main:Int()
	game = New MyGame()
	Return True
End

Class MyGame Extends App
	Field level:Level
-----
End

Class Level
  Field Tiles:TileMap


In your other files you need to import Main:
Player.monkey
Import Main


And to use Tiles in Player.monkey, you can either refer to the variable directly or you could get a Getter/Setter in your Level class:

Class Player

  Method Collide:Void()
    if game.level.Collide(self) Then ...
  End



tiresius(Posted 2015) [#4]
Just a warning... although the temptation is great, using Globals (including Singleton pattern) can produce unwanted coupling among objects. I'm not good enough at OOP yet to offer better solutions, just figured I would mention it. :)


Derron(Posted 2015) [#5]
@Coupling in singletons:

singleton: MySingletonBase
singleton: MySingleton extends MySingletonBase

MySingleton checks on "getInstance()" if the type is already MySingleton, if not, create one out of the parental "MySingletonBase".
From now on the "instance" of both singletons will return the "MySingleton" type.

Files of course call it from the "uncoupled" MySingletonBase-file. So they do not know much about the real functionality which is used. This is similar to "interfaces". There might be better approaches to this, but I use such an approach in BlitzMax because some functionality isnt available there.

bye
Ron


Fryman(Posted 2015) [#6]
I tried the original suggestion you made first therevills however I got "You cannot access TileMap.CollisionTile from here" (im Using Diddy for tilemaps) which is why I had the request. Using Globals for just the mapping it working for me but really as I said earlier its not very well organised in code, Im doing all shooting calculations in Player.Main when really I could of created a Bullet object and looped them in main.monkey passing the information to them that way.

As with your reply tiresuis I will bear that in mind, my OOP or even programming in general isn't that great either. So its a nice lesson for me to learn to use in the future.
Although your example Derron went right over my head.


therevills(Posted 2015) [#7]
How do you refer to tilemap? Could you show us some code?


Fryman(Posted 2015) [#8]
Can try, here is some stripped out code with just the tilemap and the problem call from player.main
this is the example where using Field gives me the cannot access from here error and Global works

Mapping.Monkey - Contains the code for drawing a tilemap, pretty much a clone of the diddy example
'Loads up a tiled map for use as the playfield, code uses the diddy module for its tileset loading
'Layer one should be called "Tile Layer 1" The collisions Layer should be called "Collisions Layer 1"


Import mojo
Import diddy

Const ScreenWidth = Int 640
Const ScreenHeight:Int = 480


Public Class ClassTiles
'	Field TileMap:MyTileMap
	Field str:String
	Field TileMap:MyTileMap
	Field OffSetX:Int
	Field OffSetY:Int
	'Call me to load up a new tileset for the background map
	Method Initialise(TileSetFile:String, MapFile:String)
		diddyGame.images.LoadAnim(TileSetFile, 20, 20, 21, Null, True, False)
		Local reader:MyTiledTileMapReader = New MyTiledTileMapReader
		Local tm:TileMap = reader.LoadMap("maps/"+MapFile)
		TileMap = MyTileMap(tm)
	End Method
	
	Method DrawTiles()
		TileMap.RenderMap(OffSetX, OffSetY, ScreenWidth, ScreenHeight)

	End Method
	
	'Code in original example file, no idea what it does but it is called on exit. Code brings up an error if used
	Method UpdateTiles()
	'	TileMap.UpdateAnimation(dt.frametime)
	End Method
	
End Class

Class MyTiledTileMapReader Extends TiledTileMapReader
	Method CreateMap:TileMap()
		Return New MyTileMap
	End
End

Class MyTileMap Extends TileMap
	Method PreRenderLayer:Void(tileLayer:TileMapLayer)
		SetAlpha(tileLayer.opacity)
	End
End


Player.Monkey - This has the player and shooting functions normally

this line beings up the error
If BulletX[CounterA] > ScreenWidth Or BulletY[CounterA] > ScreenHeight Or BulletX[CounterA] < 0 Or Game.Mapping.TileMap.CollisionTile(BulletX[CounterA]+Game.Mapping.OffSetX, BulletY[CounterA]+Game.Mapping.OffSetY, "Collisions Layer") > 0 Then



Import Mojo
Import diddy
Import Main

Const ScreenHeight:Int = 480
Const ScreenWidth:Int = 640

Class ClassPlayer
	Field X:Int = 200
	Field Y:Int = 300
	Field Speed:Int = 5
	Field BulletX:Float[100]
	Field BulletY:Float[100]
	Field BulletSpeed:Float[100]
	Field BulletAngle:Float[100]
	Field BulletCount:Int = 0
	Field BulletTimer:Float = Millisecs()
	


	Method SortBulletsArray()
		Local CounterA:Int
		Local CounterB:Int
		'If the bullet has gone off the screen do something about it (remove it from the array and then sort the rest)
		For CounterA = 0 To BulletCount
			If BulletX[CounterA] > ScreenWidth Or BulletY[CounterA] > ScreenHeight Or BulletX[CounterA] < 0 Or Game.Mapping.TileMap.CollisionTile(BulletX[CounterA]+Game.Mapping.OffSetX, BulletY[CounterA]+Game.Mapping.OffSetY, "Collisions Layer") > 0 Then
			'Move all the bullets after the null one down the array, then reduce the counter
			For CounterB = CounterA To BulletCount-1
					BulletX[CounterB] = BulletX[CounterB+1]
					BulletY[CounterB] = BulletY[CounterB+1]
					BulletSpeed[CounterB] = BulletSpeed[CounterB+1]
					BulletAngle[CounterB] = BulletAngle[CounterB+1]
				Next
			BulletCount -= 1 'Remove the bullet from the count
			End If
			
		Next
	End Method

End Class


Main.Monkey - Main game loop, initialises maps etc
'language imports
Import mojo
Import diddy

'Project imports
Import input 'contains keys for rebinding
Import player
Import mapping
Function Main()
	New Game()
End Function

Class Game Extends DiddyApp
	Field Player:ClassPlayer
	Field Input:ClassInput
	Field Mapping:ClassTiles 'Causes error switching field for global makes it work
	
	Method OnCreate()
		SetUpdateRate(120)
		Player = New ClassPlayer
		Mapping = New ClassTiles
		Mapping.Initialise("tileslostgarden.png", "map.xml")
		Player.Initialise()
	End Method
	
	Method OnRender()
		Cls(0, 0, 0)
		Mapping.DrawTiles
	End Method
	
	Method OnUpdate()
		CheckInput
		Player.UpdateBullets
		
	End Method
	
	Method CheckInput()
		If KeyDown(C_KEY_DOWN) And Mapping.TileMap.CollisionTile(Player.X+Mapping.OffSetX, Player.Y+11+Mapping.OffSetY, "Collisions Layer") < 1 Then Mapping.OffSetY += 1
		If KeyDown(C_KEY_UP) And Mapping.TileMap.CollisionTile(Player.X+Mapping.OffSetX, Player.Y-1+Mapping.OffSetY, "Collisions Layer") < 1 Then Mapping.OffSetY -= 1
		If KeyDown(C_KEY_LEFT) And Mapping.TileMap.CollisionTile(Player.X-1+Mapping.OffSetX, Player.Y+Mapping.OffSetY, "Collisions Layer") < 1 Then Mapping.OffSetX -= 1
		If KeyDown(C_KEY_RIGHT) And Mapping.TileMap.CollisionTile(Player.X+11+Mapping.OffSetX, Player.Y+Mapping.OffSetY, "Collisions Layer") < 1 Then Mapping.OffSetX += 1
		
		If KeyHit(C_KEY_SHOOT) Then Player.Shoot("") 'Check is the player is shooting, use keyhit so it doesnt try to spam bullets
		If MouseDown(MOUSE_LEFT) And MouseOnUI = False Then Player.Shoot("")
		'Test code for player collisions with map
		If MouseHit(MOUSE_RIGHT) Then Print Mapping.TileMap.CollisionTile(Player.X+Mapping.OffSetX, Player.Y+Mapping.OffSetY, "Collisions Layer")
	
	End Method
	
End Class



Samah(Posted 2015) [#9]
You're trying to access an instance-level field as if it were static. I'm assuming you meant to use diddyGame.Mapping rather than Game.Mapping.


Fryman(Posted 2015) [#10]
I used Game.Mapping as Game is the class which contains the Mapping field?


Samah(Posted 2015) [#11]
Right, but you're trying to access it statically rather than on an instance of the Game class. When you instantiate the Game class, Diddy automatically assigns it to the diddyGame global variable. Because diddyGame is declared as type DiddyApp rather than your custom class, you will also need to typecast it.
Rather than Game.Mapping, use Game(diddyGame).Mapping


Fryman(Posted 2015) [#12]
Ahhh ha, well learnt something new :)

I should really look up all this boilerplate code I use as I bet I have no idea what the majority of it is actually doing behind the scenes.

Thank you all for your help


Samah(Posted 2015) [#13]
The instance/static thing gets everyone to start with. ;)