NandoSoft
Level 1
|
|
« on: July 12, 2010, 07:33:28 AM » |
|
So Im making a game once again and Im facing some troubles designing the engine So I have my main class where the game loop runs, the level class which renders the level and can also tell you if a section of it is collidable or not. And finally I have the Character class which draws the character so my problem is that I dont know how to hook up the level class to the character list since the level class is instantiated in the main class the character class does not have access to the level class unless (I make the level class static, a bad idea, or I send an instance of the level class to the constructor of the character class) so basically my problem is when in a object oriented design I dont know how to make 2 different classes make notice of each other. Its is a pain to me because I tend to implement my programs in a waterfall-method like fashion Hope Im making myself clear thanks for reading
|
|
|
Logged
|
|
|
|
Matt Thorson
|
|
« Reply #1 on: July 12, 2010, 09:37:44 AM » |
|
I think the usual method is:
Main has a Level has a GameObject
Then Main.render() calls Level.render() calls GameObject.render() and Main.update() calls Level.update() calls GameObject.update()
|
|
|
Logged
|
|
|
|
NandoSoft
Level 1
|
|
« Reply #2 on: July 12, 2010, 09:40:50 AM » |
|
ah okay sounds simple enough so I either pass my objects list to the level class at load time or just at the draw/update calls
|
|
|
Logged
|
|
|
|
Matt Thorson
|
|
« Reply #3 on: July 12, 2010, 09:54:59 AM » |
|
In Flash things have to be added to the stage, then the stage keeps references to all the display objects until they are removed. That's usually how I handle it in my engines too - Level.add(GameObject) and Level.remove(GameObject).
If GameObjects need a reference to the Level, your GameObject constructor could take a Level argument, or your GameObject.update()/.render() could take a Level argument.
|
|
|
Logged
|
|
|
|
BadgerManufactureInc
Guest
|
|
« Reply #4 on: July 12, 2010, 03:30:51 PM » |
|
Yes as Matt says you should add objects to your main class in your required order of depth. Generally inter-class communicaiton is not necessary if you make your Character classes variables public and modify or set those properties from you main class. If you however require to access Level variables from within a Character object for example then you do need to pass it to Character when you instantiate the character. Say your character classes constructor looks like this at the moment: public var x:int; public var y:int;
public function Character(XPOS:int,YPOS:int):void { .. x=XPOS; y=YPOS; .. } and you create a character in your main class like this: var myChar:Character=new Character(200,200); Then you need to expand on the constructor like this, also creating a new tiles array class var in Character: public var x:int; public var y:int; public var tiles:Array=[];
public function Character(XPOS:int,YPOS:int,TILES:Array):void { .. x=XPOS; y=YPOS; tiles=TILES; .. } And now instantiate this way: var myChar:Character=new Character(200,200,tilemap); You can now acces your tilemap in the character class. If you need to see it the other way around (to access Player data in your Level class) then dont hesitate to ask. My advice would be don't make inter class communicate unless you need to, ie don't do it for the sake of future proofing but instead only when you need to. Others may tell you different, which I can accept.
|
|
« Last Edit: July 12, 2010, 03:34:29 PM by BadgerManufactureInc »
|
Logged
|
|
|
|
muku
|
|
« Reply #5 on: July 12, 2010, 11:33:52 PM » |
|
What I generally do is make the main game class a global or singleton. Via that, all game objects can access the level, the timer and whatever else they may have a need for. Yeah, sue me. But in all honesty, there will only ever be one game running at a time, so I don't want to go to the hassle of passing what is logically a global around to all game objects. Just not worth it.
|
|
|
Logged
|
|
|
|
oahda
|
|
« Reply #6 on: July 13, 2010, 02:31:49 AM » |
|
Another possibility is to have a static Level *const getCurrentLevel() or something like that in the class that handles the game, so that you can access it from the character class.
|
|
|
Logged
|
|
|
|
NandoSoft
Level 1
|
|
« Reply #7 on: July 13, 2010, 07:54:45 AM » |
|
thank you for so many replys u guys rock!
|
|
|
Logged
|
|
|
|
Matt Thorson
|
|
« Reply #8 on: July 13, 2010, 09:22:24 AM » |
|
Yeah in practice I'll make Main a singleton and have a static reference to it, available to all other classes.
Then everything can access Main.currentLevel, etc.
|
|
|
Logged
|
|
|
|
Jonathan Whiting
|
|
« Reply #9 on: July 15, 2010, 05:35:30 AM » |
|
What I generally do is make the main game class a global or singleton. Via that, all game objects can access the level, the timer and whatever else they may have a need for.
This has always been the most practical method for me. It's arguably a bit weak as an OOP practice, but it gets stuff done, which is far more important imho.
|
|
|
Logged
|
|
|
|
InfiniteStateMachine
|
|
« Reply #10 on: July 15, 2010, 08:42:43 AM » |
|
so far I've been doing a singleton type global reference too. I'm pretty new to coding so I was a little worried about doing it that way, glad to see that others are doing it too
|
|
|
Logged
|
|
|
|
Triplefox
|
|
« Reply #11 on: July 15, 2010, 09:14:59 AM » |
|
I've gravitated towards keeping the hierarchy like so:
App Game Level <components>
It's mainly a matter of how much state I want to preserve. Leaving it in an object means that I can reset easily by instancing a new one on top of the old one and letting the GC do everything else. So the bulk of the gameplay data is running somewhere within Level, while App stores global user settings and basic resource management, and Game stores cross-level information.
The main loop, including all the titles and menus, ends up getting sliced between Game and Level(though I'll tend to factor a lot of the menu code into another file). Those two have the most interdependency of any of the classes, with the components running a close second. The only way I can see to reduce that is to bloat up the code with a lot of unnecessary indirection(e.g. an event system; events can be useful once you have a rich set of behaviors to attach piecemeal to different AIs, but I've struggled to find a purpose for them on a core architecture level).
The entity data layout is optimized to simplify batch updates of each component, hence the entity itself only has an id reference and destructors - you have to use each component's access methods to learn the state in more detail. AI is just another kind of component, aware of the others.
Components have a backreference to the level instance, but that and a backreference from the level to the game are basically the only cases where I do it two-way; it's an architectural optimization specific to Flash, since Flash makes local and instance lookups cheap and static ones expensive. (yes, even static methods.)
I also use object pools for each component and for entity instances. Flash doesn't have generational collection so this strategy pays off for optimization, plus it gives you an easy(albeit imperfect) check for memory-leaking code - cap the pool and throw an exception if it overflows.
|
|
|
Logged
|
|
|
|
B_ill
|
|
« Reply #12 on: July 15, 2010, 09:33:59 AM » |
|
Where do you guys tend to stick your menus in the hierarchy of things? I usually use a structure similar to the one championed here, and it's usually a part of "game" parallel to "level"
|
|
|
Logged
|
Game Programmer and Designer Latest Release: Chemical Cubes for Android and Kindle Fire (iOS coming soon)
|
|
|
muku
|
|
« Reply #13 on: July 15, 2010, 10:01:53 AM » |
|
Where do you guys tend to stick your menus in the hierarchy of things? I usually use a structure similar to the one championed here, and it's usually a part of "game" parallel to "level"
I tend to have a stack of "screens", which have update and render methods. For instance, you'd have a TitleScreen, MainMenuScreen, OptionsScreen, and so on. Every screen can choose to push a child screen onto the stack or replace itself with a successor screen. You can also implement a system of "transparent" screens such that you can, for instance, render a PauseScreen on top of your main Game screen.
|
|
|
Logged
|
|
|
|
Jonathan Whiting
|
|
« Reply #14 on: July 15, 2010, 10:35:03 AM » |
|
I tend to have a stack of "screens", which have update and render methods. For instance, you'd have a TitleScreen, MainMenuScreen, OptionsScreen, and so on. Every screen can choose to push a child screen onto the stack or replace itself with a successor screen.
I do exactly this too, it's simple but powerful, and importantly makes adding new screens very simple. If I have screens that share common functionality I'll dump that functionality into 'component' style classes, so my Main Menu screen might contain a List Menu component with it's own update and render methods. I'll generally favour keeping such components very lightweight, and do any screen specific behaviour in the screen classes.
|
|
|
Logged
|
|
|
|
Average Software
|
|
« Reply #15 on: July 15, 2010, 12:30:57 PM » |
|
I've always modeled a state machine. I have an abstract Logic type with a Process operation that conducts one frame of action, and returns the next state. The main loop checks to see if the state has changed, and if it has it releases the old state. It looks something like this: package Logics is pragma Elaborate_Body;
type Logic is abstract new Limited_Controlled with private; type Logic_Access is access all Logic'Class;
--Snip
-- New operations. -- Logic driving procedure. Passes the next logic state in the -- out parameter. If the parameter comes back null, a quit has -- been requested. not overriding procedure Process(This: in out Logic; Next: out Logic_Access) is abstract;
-- Snip end Logics; The individual states look like this: package Logics.Title_Screen is type State is new Logic with private;
-- Logic overrides. overriding procedure Initialize(This: in out State); overriding procedure Finalize(This: in out State); overriding procedure Process(This: in out State; Next: out Logic_Access);
-- Snip end Logic.Title_Screen; The main loop looks like this: function Main_Loop return Integer is begin -- Calculate the new delta. Tickables.Calculate_Delta;
-- Draw the screen. Renderer.Draw;
declare Next_State: Logic_Access; begin -- Process the logic, obtaining the next logic. Current_State.Process(Next_State);
-- If the logic has changed... if Next_State /= Current_State then -- Release the old logic. Free(Current_State); -- Store the new one. Current_State := Next_State;
-- A state of null is a request to die. if Current_State = null then return 0; end if; end if; end;
return 1;
exception when Error: others => Error_Out(Error);
return 0; end Main_Loop; This has always worked the best for me, it keeps things nicely isolated, since each state can be worked on completely independantly of the others.
|
|
|
Logged
|
What would John Carmack do?
|
|
|
increpare
Guest
|
|
« Reply #16 on: July 15, 2010, 02:51:41 PM » |
|
I tend to just use global variables instead of singleton stuff.
|
|
|
Logged
|
|
|
|
oahda
|
|
« Reply #17 on: July 16, 2010, 12:28:35 AM » |
|
I tend to just use global variables instead of singleton stuff.
Nasty.
|
|
|
Logged
|
|
|
|
muku
|
|
« Reply #18 on: July 16, 2010, 12:29:42 AM » |
|
I tend to just use global variables instead of singleton stuff.
Nasty. Oh, come on. You're kidding yourself if you think that a singleton is anything other than a global variable in disguise.
|
|
|
Logged
|
|
|
|
Jonathan Whiting
|
|
« Reply #19 on: July 16, 2010, 12:54:05 AM » |
|
I tend to just use global variables instead of singleton stuff.
When I'm using something that lets me do this comfortably I do, actionscript isn't particularly "global friendly" in my experience. As muku said, singleton's are globals in disguise.. Were I a better artist I'd do some sort of transformers/code mash-up thing.
|
|
|
Logged
|
|
|
|
|