Class Extends bug, using inside a stack ?
Monkey Forums/Monkey Programming/Class Extends bug, using inside a stack ?
| ||
H! I'm able to push new objects to a stack, but they don't find the methods. Its maybe not as strict as it needs to be ? Class Scene Field sprites:Stack<Sprite> = New Stack<Sprite>() Method Init:Void() sprites.Push(New World()) ' <--- WORKS, but maybe its better that its not working' sprites.Push(New Player()) ' <--- WORKS' For Local sp:Sprite = Eachin sprites sp.Load() ' <--- DON't WORK Error : Identifier 'Load' not found. Next End End Class Sprite ' sprite things AND no Load() method, don't need it here) Method MoveTo:Void(_mx:Float, _my:Float) End End Class Player Extends JSONLoader ' player things ' Method Load:Void() ' other player 'init' stuff LoadAtlas("data.json") End Method MoveTo:Void(_mx:Float, _my:Float) Super.MoveTo(_mx,_my) ' WORKS ' End End Class World Extends JSONLoader ' world things ' Method Load:Void() ' other 'world' init stuff LoadAtlas("data.json") End End Class JSONLoader Extends Sprite Method LoadAtlas:Void(inpFile:String,imgHandler:Int=0) End Method LoadOtherBla:Void() End End Not using the stack and it works, but I want to add all the 'sprites' inside a 'list' to manage them all. |
| ||
Did you use STRICT? Normally you have to cast them to their original type to have access to their own methods. The class Sprite has no Load method, that is why it isn't working. |
| ||
Yes using strict. dint know casting was possible in monkey. Going to check that |
| ||
To be fair, there's nothing in the online documentation regarding casting. |
| ||
While learning about casting is a good thing, casting is really not the way to resolve your issue based on the code you posted. If you're storing a set of "Sprites" and then believe you should be able to iterate over that set and call the Load method on them then, despite what your code comment says, you do need to have the Load method defined on Sprite. Your code implicitly states that loading is something that Sprites do. |
| ||
Adding to what muddy_shoes said, you could always make 'Sprite' an abstract class, or make 'Load' abstract. The former case being to make sure objects of that type can not be created (So, you could provide a "blank" implementation, and inheriting classes could override that). Or, if 'Load' is abstract, you wouldn't have it explicitly implemented in 'Sprite', but inheriting classes like 'Player' and 'JSONLoader' would need to either be abstract, or implement that method. |
| ||
@SamahField sprites:Stack<Sprite> = New Stack<Sprite>() sprites.Push(New Player()) sprites.Push(New World()) For Local sp:Sprite = Eachin sprites If Player(sp) Local ItsAPlayer:Player = Player(sp) ItsAPlayer.Load() End If World(sp) Local ItsAWorld:World = World(sp) ItsAWorld.Load() End Next Player and World have extends Sprite But maybe (not tested) this is working if they don't Field sprites:Stack<Object> = New Stack<Object>() sprites.Push(New Player()) sprites.Push(New World()) For Local unknownObject:Object = Eachin sprites If Player(unknownObject) Local ItsAPlayer:Player = Player(unknownObject) ItsAPlayer.Load() End If World(unknownObject) Local ItsAWorld:World = World(unknownObject) ItsAWorld.Load() End Next The reason for this setup was because I want clean Classes, without things I don't need in it. I will try to translate "Or, if 'Load' is abstract, you wouldn't have it explicitly implemented in 'Sprite', but inheriting classes like 'Player' and 'JSONLoader' would need to either be abstract, or implement that method." Into code. Don't know exactly how. |
| ||
Oke if this was not hard at all, I can live this this setup.Class Sprite Abstract Method Load:Void() Abstract ..... sprites.Push(New Player()) sprites.Push(New World()) For Local sp:Sprite = Eachin sprites sp.Load() Next So now everything is oke, and everyone is happy with my code style ;) |
| ||
I think you need to rethink your class hierarchy. This is what you currently have: Sprite JSONLoader World Player This states that all JSONLoaders are Sprites. What if I want to make a JSONLoader that isn't a Sprite? You need to think about what concepts your classes represent, and how best to write it in English (or any spoken language). Here's how I would logically explain the kind of thing you want: 1. All sprites should have a position, texture, etc. 2. The world and player have a position and texture. 3. Some objects need to be able to load JSON files. From 1 and 2 you can immediately see that World and Player should inherit the properties of Sprite. As for 3, it's quite possible that there are parts of your game that should load JSON files that DON'T need a position and texture. However, you still want World and Player to be able to load themselves. This is where you could use an interface to represent that World/Sprite "know how to load a JSON file". Class structure: Sprite World Player And now, apply an interface to World and Player: ' interface represents "the class knows how to load itself" Interface JSONLoader Method Load:Void() End Class Sprite ' sprite properties like position and texture End Class World Extends Sprite Implements JSONLoader Method Load:Void() ' load the world End End Class Player Extends Sprite Implements JSONLoader Method Load:Void() ' load the player End End And now: Field sprites:Stack<Sprite> = New Stack<Sprite>() sprites.Push(New Player()) sprites.Push(New World()) For Local sp:Sprite = Eachin sprites If JSONLoader(sp) JSONLoader(sp).Load() End Next Read the documentation for more info on interfaces. Note: Realistically you'd probably keep a separate list of things to load and add your World/Player to that so that you don't need to cast. |
| ||
I fun part is, that a month ago I started with Intefaces but it din't work like I thought is has to (poor documentation) I searched the forum and found some examples, but now it makes sense the way you explain it (using my code example) That being said, and i'm asking this before I did test it because i'm not at home right now ;( Using Interface JSONLoader Method Load:Void() End Destroys in this example my JSONLoader class, so I guess its like this. Interface IJSONLoader Method Load:Void(path:String) End Class JSONLoader ' things Method Load:Void(path:String) ' here we go End End Class World Extends Sprite Implements IJSONLoader Field theActualJSONLoader:JSONLoader = New JSONLoader() Method Load:Void(path:String) ' load the world theActualJSONLoader.Load(path) End End Field sprites:Stack<Sprite> = New Stack<Sprite>() sprites.Push(New Player()) sprites.Push(New World()) For Local sp:Sprite = Eachin sprites If IJSONLoader(sp) IJSONLoader(sp).Load("data.json") End Next Because this is of course not possible Interface JSONLoader Method Load:Void(path:String) ' here we go End End Class World Extends Sprite Implements JSONLoader Method Load:Void(path:String) ' load the world End End Field sprites:Stack<Sprite> = New Stack<Sprite>() sprites.Push(New Player()) sprites.Push(New World()) For Local sp:Sprite = Eachin sprites If JSONLoader(sp) JSONLoader(sp).Load("data.json") End Next |