It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
In games it's usual to be able to access some kind of menus.
A list of things with descriptions, a menu of upgrades, anything that's pretty heavy with pictures, text etc.
So what is a convenient way to organize it all?
As I tried classes, it seems like they don't share variables between them.
I need a way of sharing data between these windows/menus. And it shouldn't be overweighted with data, meaning each time I close a menu it's parts disappear to not make Flash calculate MovieClip positions, alphas, effects and other values that I don't need, working with another menu.
As an example to better understand, what if I make 5 games in one and need to share variables between them?
Say, first I play Arcanoid, then switch to Tetris and use Arcanoid score as a number of blocks I can get, then switch to Pinball and use the number of lines scored in Tetris as a number of balls, then switch to Gradius and my ship attack power is Pinball score divided by 1000, then I see a window of overall scores with heavy victory firework effects.
I'd need each game to work separately, otherwise they will go very slow overloaded with graphics and the length of code to find functions.
How is that achieved?
Thanks moskito, I'm a bit messy ^_^'
How is that achieved?
You create the architecture to make it happen. Your particular example could be approached like this:
Firstly, you want to define the foundation that these mini-games or separate batches of content will run on. This foundation will deal with running the mini-games, as well as tracking their state and information associated with them that you want to pass off to subsequent mini-games.
Secondly, you want to define the base class that will represent one of these mini-games. This class will be extended for each of the new games you want to create and have run on the platform. This base class will deal with notifying the platform of changes.
Lastly, you want to create some models represting a state in change within the mini-game. The inbuilt Event system is a good way to approach this, but you can easily create your own data models in this instance which you pass off to the platform directly.
Code samples.
The basics of your platform could be something along the lines of:
public class Platform
{
private var _game:MiniGame;
private var _recentGameStateData:GameStateData;
public function loadGame(game:MiniGame):void
{
if(_game != null) game.unload();
_game = game;
_game.start(this, _recentGameStateData);
}
public function update():void
{
if(_game != null) _game.update();
}
internal function manageStateChange(gameStateData:GameStateData):void
{
_recentGameStateData = gameStateData;
// Do stuff with the new game state data, like save the current score
// to use in your next game.
//
}
}
Your mini-game:
public class MiniGame
{
private var _platform:Platorm;
private var _score:int = 0;
public function start(platform:Platform, previousGameStateData:GameStateData):void
{
_platform = platform;
// Use previous GameStateData here.
//
}
public function update():void{}
public function unload():void{}
public function notifyPlatform(gameStateData:GameStateData):void
{
_platform.manageStateChange(gameStateData);
}
protected function get score():int{ return _score; }
}
Your game state data for the platform to manage:
public class GameStateData
{
private var _game:MiniGame;
private var _score:int;
public function GameStateData(game:MiniGame, score:int)
{
_game = game;
_score = score;
}
public function get game():MiniGame{ return _game; }
public function get score():int{ return _score; }
}
And then an example of sending that information up to the platform in your own mini-game:
public class TetrisGame extends MiniGame
{
override public function unload():void
{
// Let the Platform know about the current score when this game is
// being unloaded.
var state:GameStateData = new GameStateData(this, _score);
notifyPlatform(state);
}
}
Related
I am trying to make an options menu for my game where there are 2 settings. One setting disables all music that are in the game, and the other disables all sound effects. If the user chooses to disable all sound effects and not music, then when he exits the game and comes back to it, it should remember his settings. I have tried numerous times to create this sort of system, but it is not working for me at all. I don't know how to create it. Can anyone please help? I am fairly new at action script.
All sounds are accessed from library
Use SoundChannel to create and control separate sounds.
use a SharedObject to store user choice.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/SoundChannel.html
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/SharedObject.html
The answer is to use a sound manager class of static functionality, which will have two public Boolean properties which then you can set separately using your options menu. Then, the class will check these booleans each time you want a sound to be played (for this, use its function to play sounds). An example:
public class SoundManager {
private var _musicOn:Boolean;
private var _soundOn:Boolean;
private var _currentMusicChannel:SoundChannel;
private var _currentMusicSelected:Sound; // what to start when music is enabled
public static function get musicOn():Boolean { return _musicOn; }
public static function set musicOn(value:Boolean):void {
if (value==_musicOn) return;
_musicOn=value;
if (_musicOn) _currentMusicChannel=_currentMusicSelected.play();
else if (_currentMusicChannel) {
_currentMusicChannel.stop();
_currentMusicChannel=null;
}
}
public static function get soundOn():Boolean { return _soundOn; }
public static function set soundOn(value:Boolean):void { _soundOn=value; }
// a simple version, as this is an example
public static function playSound(someSound:String):void {
var aSound:Sound=getSoundFromString(someSound); // TODO
// ^ you have to devise a method to convert strings to sounds
if (isMusic(aSound)) {
// TODO, you should have either one music or a set of em, so if you're
// trying to play a music, this should return true, otherwise false
_currentMusicSelected=aSound;
if (_musicOn) _currentMusicChannel=aSound.play();
} else {
// a simpler version, the more advanced version should allow instant mute
if (_soundOn) aSound.play();
}
}
// some other functions are missing from here, as well as sound library and support stuff
}
I'm writing a game where you have to go through a maze. I want this game to have different levels. But for each level, the maze is going to be different. So I drew other walls. But I do not want to write my collision detection method 50 times if I have 50 different levels.
I thought of a way of fixing it, but it's not working. I created a new symbol with nothing in it and named it wall. I think that I can make my wall = wall1 (another symbol I converted, and exported for as), and just do stage.addChild(wall). But I can't find a way to do that. So I need help!
Make a generic class e.g. Wall and make your library symbols use that for their base class. You won't need to create them at runtime using ActionScript for this inheritance to work, you can still just place your MovieClips on the stage.
The next thing you need to do is store these Walls somewhere. Because you seem inexperienced with ActionScript, and want to avoid writing code for new levels, you can automate this process using a manager type class. We will call this class WallManager and it will look like this:
public class WallManager
{
private static var _walls:Vector.<Wall> = new <Wall>[];
internal static function register(wall:Wall):void
{
_walls.push(wall);
}
public static function reset():void
{
_walls = new <Wall>[];
}
public static function get walls():Vector.<Wall>{ return _walls; }
}
Then we'll create your Wall class. Within the constructor for this class, we will automatically have the Wall add itself into the WallManager listing:
public class Wall extends Sprite
{
public function Wall()
{
WallManager.register(this);
}
public function touchingMouse(mouseX:int, mouseY:int):Boolean
{
// For this example I am checking for collisions with the
// mouse pointer. Replace this function with your own collision
// logic for whatever it is that is supposed to collide with
// these walls.
if(parent === null) return false;
var bounds:Rectangle = getBounds(parent);
return bounds.contains(mouseX, mouseY);
}
}
This setup is not 'best practice', but it is suitable in your situation because your project seems small, you appear to be working on it alone, it's simple and it gets the job done.
At the end of each level, use WallManager.reset() to remove the walls from the previous level. For checking collisions across all walls, just use a loop like this:
for each(var i:Wall in WallManager.walls)
{
var collision:Boolean = i.touchingMouse(mouseX, mouseY);
if(collision)
{
// There was a collision.
//
//
}
}
You can make one MovieClip with 50 frames saying stop() on the first frame and do your code like this:
private var wallnum:int;
public function Main()
{
stop();
wallnum = 1;
var wallobj = new Wall();
addChild(wallobj);
wallobj.gotoAndStop(wallnum);
}
For collision detection, I recommend Pixel Perfect Collision Detection (https://code.google.com/p/master-air-controller/source/browse/trunk/master-air-controller/src/PixelPerfectCollisionDetection.as?spec=svn6&r=6)
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I'm making a game as a part of my unit for uni but I don't know the best way of doing it as i'm new to AS3. I have 8 guests in a party each different and has different personalities, hobbies and interests. The game works like this, if you click on a guest and click anywhere on stage then that guest will move towards it. If you click on a guest and then click on another guest, the guest you clicked on first will move towards the guest you clicked on second and when they are close they will talk to each other.
All the 8 guests will share the same function and code in terms of the moving around. I have got the click and move part done but it was done on a Guest01 class but all the guest will have it the same. Should I create 8 different classes for each guest or should I do it using arrays. I really don't know how to start on this. Below is the code for click and move:
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.*;
public class Guest01 extends MovieClip
{
var walkSpeed:Number = 5;
var oldPosX;
var oldPosY;
var myGlow:GlowFilter = new GlowFilter();
public function Guest01()
{
addEventListener(MouseEvent.MOUSE_OVER, addGlow);
}
public function addGlow(event:MouseEvent):void
{
filters = [myGlow];
addEventListener(MouseEvent.MOUSE_OUT, removeGlow);
addEventListener(MouseEvent.CLICK, ready);
}
function removeGlow(event:MouseEvent):void
{
filters = [];
}
public function ready(event:MouseEvent):void
{
filters = [myGlow];
stage.addEventListener(MouseEvent.MOUSE_DOWN, walk);
removeEventListener(MouseEvent.MOUSE_OUT, removeGlow);
}
function walk(event:MouseEvent):void
{
oldPosX = parent.mouseX;
oldPosY = parent.mouseY;
rotation = Math.atan2(oldPosY - y,oldPosX - x) / Math.PI * 180;
filters = [];
stage.removeEventListener(MouseEvent.MOUSE_DOWN, walk);
stage.addEventListener(Event.ENTER_FRAME, loop);
}
function loop(event:Event):void
{
var dx:Number = oldPosX - x;
var dy:Number = oldPosY - y;
var distance:Number = Math.sqrt((dx*dx)+(dy*dy));
if (distance<walkSpeed)
{
// if you are near the target, snap to it
x = oldPosX;
y = oldPosY;
removeEventListener(Event.ENTER_FRAME, loop);
}
else
{
x = x+Math.cos(rotation/180*Math.PI)*walkSpeed;
y = y+Math.sin(rotation/180*Math.PI)*walkSpeed;
}
}
}
}
I have got the click and move part done but it was done on a Guest01 class but all the guest will have it the same. Should I create 8 different classes for each guest or should I do it using arrays.
You should not create 8 different classes for 8 different Guests but you should try to re-use the classes and methods for different Guests.
I have 8 guests in a party each different and has different personalities, hobbies and interests.
You would want to create one Guest class and keep all the properties (personalities, hobbies etc.) as the variables in the class. You'll have to initialize the Class for different Guest in the start based on the profile the guest selects (or random). Also all the methods for Guest (like walk, glow etc.) would be the methods of the class itself.
Hope it helps to give you some direction.
Just tried to answer your question from a different post. You need to break down the game into simple actions like moving the user from one place to another, calculating the offset position a user should move to if they wan to move to another user, calculating the position of elements for displaying a users hobbies and interests, ect.
Have you ever programmed in an object oriented language before? There are some fundementles that you must have a firm grasp of before taking on a project like building a game. Based on your last post, your next focus should be the following methods.
Since you have already written a function for relocating a player based on a user click you should write the following functions:
Inside the clickToMove() function ( or whatever you called it). Write an if test to see if the relocating click selects an empty location or a location with a user on it. If the user is present you need to write another method for offsetting the position of the player that is to move, otherwise the players will be layered on top of each other.
I'm boarding a plane now will post again soon
So I have many objects with materials that each possess different properties (brick, glass, etc.) and are each affected differently by elemental effects. A brick material for example will be affected differently by fire or acid than a cement material. A brick that's Burning or Melting will be affected differently when another Burning/Melting effect is applied.
At this point in my game, I have an FSM but it's very simple. If I drop a fire element on a brick, it would go to the Burning state. However if I then dropped a water element on the brick, I might want the fire to go out, take/add health and change textures (or not depending on the current combination).
The point is, I have many combinations with no commonality between them so I can't create something uniform. Sometimes I need to change the texture and other times I don't. Sometimes take damage while other times add health. Sometimes I need to just do nothing in a function. At this point, the only thing I can thing of is creating a global mapping such as:
FunctionMap[ObjectMaterial][CurrentObjectState][ElementBeingApplied]
(i.e.
FunctionMap[Brick][Burning][Acid]
FunctionMap[Brick][Melting][Acid]
)
The problem is, is that this is obviously a ton of functions due to the amount of combinations available with materials and effect types. Can anyone recommend a route to take or pattern to look at?
Although not entirely relevant to the discussion, this is being made in AS3 and Away3D.
Here are some of my classes for one example:
public class Brick extends AbstractBlock implements IFireable
{
public function Brick()
{
super(this);
this.material = new BitmapMaterial(_spriteManager.GetBlockMaterial(BlockUtilities.GetMaterialMap["brick_new"]));
_type = "Brick";
/*
RulesManager.StateMap["Brick"]["OnFire"]["Water"] = some function;
RulesManager.StateMap["Brick"]["OnFire"]["Fire"] = some function;
RulesManager.StateMap["Brick"]["OnFire"]["Acid"] = some function;
RulesManager.StateMap["Brick"]["OnFire"]["Ice"] = some function;
RulesManager.StateMap["Brick"]["OnWater"]["Water"] = some function;
//and so on...there are nine different materials so I'm not liking this way
*/
}
public override function render():void
{
super.render();
}
}
public class OnFire extends AbstractDamage
{
protected var _timeStart:Number = 0;
private var _damageAccumulated:Number = 0;
public function OnFire(block:AbstractBlock,bombType:String)
{
super(block,bombType);
}
public override function enter():void
{
super.enter();
}
public override function exit():void
{
super.exit();
}
public override function update(time:Number):void
{
super.update(time);
if(_timeStart == 0)
_timeStart = time;
var time_delta:Number = (time - _timeStart)/_waitTime;
var damageToSubtract:Number = (time_delta * _damageDone);
_damageAccumulated += damageToSubtract;
_self.Integrity = _self.Integrity - _damageAccumulated;
}
}
}
Thus, a fire element could be applied to a bunch of applies. One those blocks, currently frozen, is now hit and is now changing to the OnFire state. Each block has its own state machine and the states are themselves objects as you can see.
block.FSM.changeState(new OnFire(block));
So your problem is that you have 9 * 5 * 4 combinations of effects, right? Having separate functions for each of those would not be fun to manage. But, even if it's a lot of data, you need it. I would make that data as simple as possible, then parse it. Something like:
var materialProperties = {
brick: {
fire: {
normal: {damage: 10, image: 'brick_fire.jpg'},
}
water: {
fire: {damage: 0, image: 'brick_smoking.jpg'}
}
},
//... a lot more of this ...
}
class Material
{
public var damage:int = 0;
public var image:String = '';
private var properties:Object;
private var state:String;
public function Material(properties)
{
this.properties = properties;
}
public function apply(effect:String):void
{
if(properties[effect])
{
if(properties[effect][state])
{
update(properties[effect][state]);
}
else if(properties[effect]['normal'])
{
update(properties[effect]['normal']);
}
}
state = effect;
}
private function update(properties):void
{
damage += properties.damage;
image = properties.image;
}
}
var brick = new Material(materialProperties.brick);
brick.apply('fire');
brick.apply('water');
Do you have custom classes setup? To me, this sounds like an ideal solution.
Once you map out each classes properties and abilities, object management should be trivial.
ie a Brick class which has certain states [burning, melting] and reacts differently [function calls] when it interacts [collides] with another class [Water Class].
I hope I'm not barking up the wrong tree.... If you can provide a bit more on what your looking for, im sure someone smarter than me will jump in ;)
Short answer because I believe Mr Linquist does a great job of explaining it - but it sounds to me like a job for the visitor pattern. In a nutshell, your elements (brick, concrete, etc) all allow visitors (fire, ice, acid, etc) to come and 'visit' them and apply their effects.
Hope this helps!
How would you adhere to the "Tell, don't ask" principle (henceforth "the principle") in the following simple scenario? In a Tetris game, I have Board, BlockGrid and Piece classes relevant to the following example:
public class Board
{
private var fallingPiece:Piece;
private var blockGrid:BlockGrid;
...
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
blockGrid.movePiece(fallingPiece, xDirection, yDirection);
}
}
Once fallingPiece is placed in the bottom row of BlockGrid, it should no longer be the "fallingPiece". Am I right in that I'm not violating the principle with the following?
if(blockGrid.getPiecePosition(piece).y == 0)
{
fallingPiece = null;
}
But is that really different from this, which I think clearly violates the principle?
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
if(blockGrid.getPiecePosition(piece).y > 0)
{
blockGrid.movePiece(fallingPiece, xDirection, yDirection);
}
else
{
fallingPiece = null;
}
}
I'm not assuming that I've designed these class relationships in the proper way to work with the principle. Please advice on an alternate design if that's what I'm missing.
EDIT, Proposed solution:
I went with the answers proposing "command feedback" via events. Board tells BlockGrid to move a piece. BlockGrid's movePiece method dispatches MOVED_TO or MOVE_FAILED events depending on the result, which Board can listen to and use to determine whether a piece has stopped falling. Please don't hesitate to provide feedback on this solution.
public class Board
{
...
public function Board()
{
...
blockGrid.addEventListener(PieceMoveEvent.MOVE_FAILED, onPieceMoveFailed);
...
}
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
blockGrid.movePiece(fallingPiece, xDirection, yDirection);
}
public function onPieceMoveFailed(event:MovePieceEvent):void
{
if(event.instance == currentlyFallingPiece && event.fromPosition.y != event.toPosition.y)
{
currentlyFallingPiece = null;
}
}
I think, to better follow the Tell, Don't Ask principle, you should have blockGrid notifying your Board class when fallingPiece has reaches it's resting point. In both scenarios above, you are asking blockGrid if the piece's position.y == 0 in order to determine whether or not fallingPiece should be null. Instead, you want blockGrid to tell the Board class that fallingPiece.y has hit 0.
What you are looking for is Event driven programming. You need a Listener interface with a method called .event() and an Event interface to represent the events. Objects will register with other objects ( callbacks ) to the Listener interface.
when you create a Piece and Board they should implement the Listener interface. Then you can set the Board with registerListener(board); Then when things happen inside Piece it will loop thru all the registered listeners and call .event(event) on each. Same with the Board, call board.registerListener(piece) each time you create a new piece, as it decides things are happening it can tell all the registered listeners what has happened. Then you can tell a piece it is no longer falling by the Board object deciding this. Here is the obligitory Wikipedia entry.
I would expect a class representing each shape (without position information), a controller containing a shape, position and orientation, and another class representing the current resulting grid of "landed" shapes. The landed-grid would have a
testLanded(shape, shapePosition, orientation)
method which would be called before/after each move operation to decide if the shape is to join the landed grid or should move and stay as the falling piece.
I'm going on the idea of not giving data to objects that shouldn't really own that data - but I've never implemented Tetris...
You may need to rethink your design. Does Board really need to track the falling piece or should that belong to BlockGrid? Iron out who owns what behavior.
Keep position information on your Piece class and possibly have your Piece class hold an instance of the BlockGrid.
You can then try something like this in your Board class...
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
blockGrid.moveFallingPiece(xDirection, yDirection);
}
Then in BlockGrid's moveFallingPiece method...
public function moveFallingPiece(xDirection:int, yDirection:int):void
{
fallingPiece.move(xDirection, yDirection);
}
In Piece's move method, add your logic...
public function move(xDirection:int, yDirection:int):void
{
setPosition(xDirection, yDirection);
if (getPosition().y <= 0)
{
blockGrid.setFallingPiece(null);
// this can bubble up to Board if need be
}
}
Not sure of all the power of AS3, but it would make sense to use abstractions here. (i.e., have your Piece class depend on ITrackFallingPieces instead of BlockGrid and have BlockGrid implement ITrackFallingPieces).
Good luck!