I'm in the process of developing an advanced modular GUI system. I need it to be as flexible as possible and hopefully as useful to as many people as possible (however it will be reasonably niche).
The part of my design that is causing me to think, is how each component should best interact with the rest of the application.
I see two approaches:
Pass in the class and name of a setter, on which the component should act upon. This still allows events to be dispatched from within the setter if desired.
Pass in a CustomEvent which the component should dispatch, with relevant data. Though I feel this may lead to a lot of Event Listeners, and extra complexity.
But What is best practice? What are the pros and cons of each? Is there a better method?
Basic example:
public class Button extends Sprite
{
private var _property:String;
private var _object:*;
public function Button(label:String, object:*, property:String)
{
_property = property;
_object = object;
addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void
{
_object[_property] = "Changed";
}
}
Basic Example:
public class Button extends Sprite
{
private var _event:GuiEvent;
public function Button(label:String, event:GuiEvent)
{
_event = event;
addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void
{
dispatchEvent(new GuiEvent(_event.type, "Changed"));
}
}
If you want your GUI framework to be useful to everybody, you should use standard events instead of inventing new ones. The second option is the way to go but you should try to keep things simple. The code you wrote in example 2 seems incredibly complicated. It could simply be written like that:
public class Button extends Sprite
{
public function Button(label:String)
{
}
}
Then anybody can handle clicks using the event they know:
button.addEventListener(MouseEvent.CLICK, onClick);
Slightly offtopic and not really an answer to your question:
Why recreate something that already exists? There are already proven libraries with GUI components.
For example, take the AS3 Temple Library
http://code.google.com/p/templelibrary/
It has all types of form element components; checkbox, radiobutton, combobox, inputfield, filefield, scrollcomponent, date selectors, (step)sliders, list, scrollbars, autocomplete field and all types of buttons.
It also has a Form class, whichs helps in validation, deliver data to any type of services. It also manages the tabindexes right and all controls can be used with keyboard too, just like everyone expects it to work. There are also codecomponents for a mockup, but you can use the same code to style it with endless creativity with library items, timelines, or however you want it. Most of the gui components are designed so they can be extended to make it fit your needs.
Most of the gui components work with normal eventlisteners (most dispatch Event.CHANGE when content change), in most cases there is no need to wrap it into new type of events.
Related
This is related to a similar question I just asked; however, this one is specifically tailored to my individual project, rather than object-oriented programming in general.
I am working on a version of hangman with some interesting programming twists. I don't need to go into detail of what they are as the logic for the game is already finished. I can run an entire game by hard-coding variables for the user input (such as guess selection). I am now in the process of replacing all those bits that require user interaction with the trappings of an actual game like buttons, images, sounds, etc.
I am trying to figure out whether it is better to have all of this stuff be part of my main class, or whether I should create another class to handle it all. For example, I want my players to be able to click on an on-screen keyboard to make their guess, with each button firing a separate event listener call to the makeGuess function. Would it be better to create the buttons as direct children of my main game class, or should I create a subclass (called Keyboard, for example) that creates the keyboard section of the board with the appropriate events, then add the keyboard class as a child to the main rather than all the pieces? What are the pros and cons of each of these choices?
For the record, I'm programming using FlashDevelop, so nothing like a timeline for me.
I say you'd better create at least the Keyboard class that will parse the events fired by tapping/clicking keys inside, and give it a callback reference to your Main class, or GameLogic class, so that it can do theMain.guess(letter); and then the Main class logic will come to life and process the callback. Since this structure is not exactly related to game logic, and technically it can then be reused by implementing an interface for the callback, so that you can use this keyboard elsewhere where you want to have your player to type letters using mouse, it's better be separated from main logic.
public class Keyboard extends Sprite {
public var callback:AcceptingKeys; // an interface
... // class implementation, with all the listeners, children and stuff
// and you call in there: callback.acceptKey(key);
}
public interface AcceptingKeys {
public function acceptKey(key:String):void; // or whatever type you need
}
And you do with your Main class:
public class Main extends Sprite
implements AcceptingKeys {
...
var keyboard:Keyboard;
private function init(e:Event=null):void {
... // other code. It's FD, then this function exists
keyboard=new Keyboard();
keyboard.callback=this;
// past this point your instances can talk
}
public function acceptKey(key:String):void {
// match interface description
... // do game logic for parsing a key
}
}
I want to make new .AS files for each and every object in my game for the sake of versatility, dynamism, and organization. I mean, in the case of a shooter game, I want to make a new class file for every type of bullet with all of their unique properties all spelled out in their respective classes. I want to do the same thing for every type of enemy in the game.
This is all assuming there may be 10+ different types of enemies/bullets.
Some people have been pushing me to keep the values of each type of, for example, bullet in one class and then just change the variables depending on the type of bullet being fired. That doesn't sound too fun to me and I would rather just create a bunch of different class files and just push all of the bullets into a common array(which works so far), but I would really like to know if I have the right, or even good, idea by doing so.
In my opinion, since bullets (or enemies, for that matter) represent the same family objects, it would make sense to have a common interface, or an abstract class, which is implemented, or extended by each concrete class. Is this a good idea? Let's think about it this way:
When you are creating the classes that will be used throughout your application, you essentially building an API. Good practice suggests that you should always program to an interface rather than an implementation. What this means is that your top-level classes, should not depend on low-level ones, but rather they should use abstractions. That way, the different-level components are loosely coupled and the overall code is more flexible. This principle is known as Dependency inversion, and is one of the five principles of the SOLID design.
The links provided should give some additional information on how to structure your code.
Have a great day!
You'll want to use inheritance to make it cleaner and more flexible with changes. Then even on multiple projects you can just extend the same generic base class.
Start with a base class (or interface) - Bullet.as for example - and put all the functionality and properties that are common to ALL bullets in that class. Anytime you have groups of bullets that share the same properties, keep making sub-classes. So if you had multiple kinds of bullets that all explode on contact, you could have the following kind of setup:
public class Bullet {
public function fire():void {};
public property size:int;
public property strength:Number;
public property label:String;
public property maxDistance:Number;
}
public class ExplodingBullet extends Bullet {
public property blastRadius:Number;
public function explode():void {
trace("Kaboom");
}
}
public class BazookaBullet extends ExplodingBullet {
public function BazookaBullet():void {
blastRadius = 10;
label = "Bazooka";
size = 5;
maxDistance = 120;
}
}
This would give your bazooka bullets all the functionality of the class it extends. There are a great many benefits to doing it this way as opposed to recreating all the same properties and methods in all your bullet classes.
I'm trying to figure out how best to setup a kind of universal game element class for my game. What I want to try and create is a structure similar too..
GameElementPositionMovement (root class)
->GameElementVisual (handles all the graphics)
->GameElementPersonality (handles game logic)
I then want to be able to set up different personalities (monster, hero, icon etc) just by creating an instance of GameElementPersonality, but in it's constructor also be able to setup the visual and positioning/movement aspects as well.
I mentioned this in another question, and the answer that came back was...
It seems that you need kind of 'data model' class to store logic and a
visual ('view') class. Visual class shouldn't inherit from data model,
it should use it. This is OOP related problem: IS vs HAS (inheritance
vs composition)
But I'm not sure if I understand that. The position/movement without any visual data, seems a good first root class, and then you add to that the visual aspects (GameElementVisual), and then finally you add in personality "traits" (GameElementPersonality) such as armour, damage, health etc
Therefore I'm keeping, the positioning/movement, visual and logic separate, and I presumed the heirachy that I've laid out would be the best way to do that, but is this not a good way to do this? should it be more flat? with the GameElementPositionMovement, creating both a visual and logic instance and storing that in itself?
You could create a structure similar to this:
(pseudocode)
ElementData
//it doesn't have to extend any particular class
//however it would be nice if it could dispatch events and register listeners
class ElementData implements IEventDispatcher
{
public function ElementData() //constructor
{
//do some stuff
}
public function setSomeProperty(value:int):void
{
//
}
public function doSomeCrazyStuff():void
{
//
}
}
ElementVisual
class ElementVisual extends MovieClip //or just Sprite or even DiplayObjectContainer
{
public function ElementVisual(elementData)
{
//constructor takes an instance of ElementData class
elementData.addEventListener(CHANGE, onDataChange)
elementData.doSomeCrazyStuff();
if (userCliked)
{
elementData.setSomeProperty(15);
}
//you can have here some interactions with user (keyboard, mouse)
//then it can communicate with elenemtData and 'listen' what it says.
}
function onDataChange
{
//react accordingly
}
}
some visual representation (you may need many of these)
class Monster extends ElementVisual
{
//do all the graphic, animations etc
}
Then you need a class to set up all the data, visuals etc… In simplest implementation it can be the 'document class'.
It's not a proper MVC model - it's a simple example to show the concept of decoupling logic from visualisation.
MVC is not the only solution, there are other so called 'design patterns' which may be useful...
Yeah the idea with MVC is to keep things decoupled, in your case you're ultimately smashing everything into one chain of inheritance where you'll end up with one type of object that inherits all the properties from another object that inherits all the properties from another object, so you'll have an instance of this thing that represents everything, which is why this isn't a great pattern to go with.
If instead you have a GameElementPositionMovement class (Your main class) create an instance of the GameElementVisual and in instance of GameElementPersonality (or multiple instances if need be). Then any time a change to a property is made in GameElementPersonality (or any in the collection if you choose to make a collection) could dispatch an event, the main class GameElementPositionMovement could listen for the dispatched event and when it gets it can set/pass the GameElementPersonality instance or array to the GameElementVisual. Then in the GameElementVisual you're just dealing with drawing based on the current model all the time, the model is separated from the view logic, you'd also probably want to handle control in a separate class or in GameElementPositionMovement. (control being the modification of the model, in this case it would probably also be where you register listeners for user events, keyboard, mouse whatever)
This way the model remains clean of control logic and view logic, it's a clear separation of what goes where and really only the view sort of depends on the model and the controller sort of depends on the view but if interfaces are established for what the model view controller each need to communicate with each other in this way you can swap out any of those parts with a new class that implements the interface (not likely an issue in a small game, but the design lends itself to this ability and therefor future scalability).
In my main Actionscript file i have a instance of a body class that moves the person body arms legs etc. and a gun class which has methods and properties to do with the person gun.
Right now i have a function in the Main class which is called move gun and looks like this and is called everyframe to move the gun to the bodys arm. I was hoping to move this function to the guns class so i could call it like gun.moveGun(); but the body dosent exist inside the gun variable. so i wonder if i could call the body.getArm(); function from inside the gun. I know i could call the function and pass the bodys arm location to it from the main file. But don't know if this is the best way to do it.
private function moveGun():void
{
gun.x = body.getArm('left').x;
gun.y = body.getArm('left').y;
}
It seems like keeping the gun related functions inside the gun class is the best way to organise everything but i dont know how to do this.
Also depending what button someone clicks at the start the person will either have a basketBall or gun in there hand. Ive added the swf online at Here so you can see how it works. i just wanna change how its organised because the main file is very full and though i should learn how to organise things better. There are lots of other part of the program that would be organised better if i knew how to get the object to interact or what is the best way to do it. Starting to think passing the x,y coordinates to the moveGun function inside the gun Class is the best way. If so just tell me please and ill do that.
From the code you posted, I think you need to move the gun with every frame to stick to the player's arm.
The answer you're looking for is Composition, since every person gets one and only one gun, I think you better put a reference (variable) in the person class for its gun.
and here is your player (person) class:
class Person
{
private var m_gun:Gun;
public function Person()
{
this.m_gun = new Gun();
}
// a function which is called each frame
private function updateFrame()
{
// Here you can provide your own logic in Gun class
this.m_gun.doSomething();
}
}
generally, you want to communicate between classes using the built-in event listener and dispatcher system. if 'something' happens - regardless of 'where' that occurs - dispatch an event. whenever something should react, it should have a listener.
for example, from the main class you mentioned, you might want to dispatch an event:
private function moveGun():void
{
var e:Event = new Event('moveGun', true);
dispatchEvent(e);
}
then the appropriate instance (the body? - not sure how you have things set up) listen for that:
body.addEventListener('moveGun', moveGunHandler, false, 0, true);
function moveGunHandler(event:Event):void{
gun.x = body.getArm('left').x;
gun.y = body.getArm('left').y;
}
the above is obviously psuedo-code since i have no way of knowing how your display list is set up. also, i used simple string literal event types - best practice would probably be to use custom event classes with event types defined as static constants.
Hopefully you will excuse me if this is a simple/silly question. I started learning action script about 6 days ago and already working on a small project :D
Anyways, there is a property that changes occasionally to reflect the name of a level in a game (object._I._M.text). It could take a minute to change, or a max of two minutes, depending on how fast all players are able to finish the level.
I want to be able to listen for the change in this property to fire off another function. I have found very few answers to this online, and the examples I have found were very incomplete and poorly written. Does anyone know how I could do this?
I have tried ...
theobject._I._M.addEventListener(Event.CHANGE, myfunction);
To no success. Thanks for any help or advice, I am going to get back to learning while I await responses :D
I would probably use getters/setters, or just declare one method to change the text of that textfield so that you can dispatch an event every time.
function changeLevel(text:String):void {
levelTf.text=text;
dispatchEvent(new Event("levelChange"));
}
I'll agree the Adobe docs are a bit "heavy" to look through. A good resource is the kirupa forum.
As for the TextField change event listener, your original code is very close. Here is a good example of how to add an event listener. The basics are:
public class Main extends Sprite {
// Store a reference to the text field
// (you're already doing this somewhere, so adapt as you see fit)
private var inputfield:TextField = new TextField();
public function Main() {
// Make sure the field is added to an on-screen Sprite
addChild(inputfield);
// Add the event listener.
// I recommend adding the 'false, 0, true' params. There are lengthy
// discussions around about this.
inputfield.addEventListener(Event.CHANGE, changeListener, false, 0, true);
}
// This function gets called every time the event is fired.
private function changeListener (e:Event):void {
trace("event");
}
}
Hopefully that gets you started in the right direction.