Reputation: 35
I am following an avoider game tutorial and can't seem to get a value to update in all parts of my class.
package
{
import flash.display.Sprite;
import flash.text.TextField
import flash.text.TextFormat
public class Score extends Sprite
{
public var scoreDisplay:String;
public var currentValue:int;
public function Score()
{
updateDisplay()
}
public function updateDisplay():void
{
scoreDisplay = currentValue.toString();
var format:TextFormat = new TextFormat();
format.size = 25;
format.font = "Verdana"
var myText:TextField = new TextField();
myText.defaultTextFormat = format;
myText.text = scoreDisplay;
myText.background = true;
myText.autoSize
myText.width = 50;
myText.height = 35;
addChild(myText)
myText.x = 340
myText.y = 10
myText.mouseEnabled = false
}
public function addToValue( amountToAdd:Number ):void
{
currentValue = currentValue + amountToAdd;
}
}
}
Whenever I run a trace for 'currentValue' inside of 'addToValue' it is updating by increments of 10 but a trace for 'currentValue' inside of 'updateDisplay' always has a value of 0. I absolutely can not figure out why the one 'currentValue' is not updating the other.
EDIT 1:
package
{
import flash.display.Sprite;
public class Start extends Sprite
{
public var game:Game;
public var gameover:GameOver;
public var background:Sprite;
public function Start()
{
background = new Sprite
background.graphics.beginFill(0xC0C0C0)
background.graphics.drawRect(0, 0, 400, 300)
background.graphics.endFill();
addChild(background)
var score:Score = new Score()
addChild(score)
game = new Game();
game.addEventListener(AvatarEvent.DEAD, startOver);
addChild(game);
}
public function startOver(avatarEvent:AvatarEvent):void
{
game.removeEventListener(AvatarEvent.DEAD, startOver);
gameover = new GameOver();
gameover.addEventListener(NavigationEvent.RESTART, requestRestart);
removeChild(game)
addChild(gameover);
}
private function requestRestart(e:NavigationEvent):void
{
restartGame();
}
public function restartGame():void
{
gameover.removeEventListener(NavigationEvent.RESTART, requestRestart);
game = new Game();
game.addEventListener(AvatarEvent.DEAD, startOver);
addChild(game);
removeChild(gameover);
}
}
}
EDIT 2
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.Timer;
import Score;
public class Game extends Sprite
{
public var army:Array;
public var gameTimer:Timer;
public var player:Player;
public var background:Sprite;
private var instanceScore:Score
public function Game()
{
army = new Array();
var newenemy:Enemy = new Enemy(100, -15);
army.push(newenemy);
addChild(newenemy);
player = new Player();
addChild(player);
player.x = mouseX;
player.y = mouseY;
gameTimer = new Timer(20);
gameTimer.addEventListener(TimerEvent.TIMER, move);
gameTimer.addEventListener(TimerEvent.TIMER, onTick);
gameTimer.start();
instanceScore = new Score();
}
private function move(timerEvent:TimerEvent):void
{
player.x = mouseX;
player.y = mouseY;
for each (var enemy:Enemy in army)
{
enemy.moveDownABit();
if (player.hitTestObject(enemy))
{
gameTimer.stop();
dispatchEvent( new AvatarEvent( AvatarEvent.DEAD));
}
}
}
public function onTick(e:Event):void
{
if (Math.random() < .1)
{
var randomX:Number = Math.random() * 400;
var newEnemy:Enemy = new Enemy(randomX, -15);
army.push(newEnemy);
addChild(newEnemy);
instanceScore.addToValue(10)
var score:Score = new Score()
addChild(score)
}
}
}
}
Upvotes: 0
Views: 837
Reputation: 3951
In addToValue
call updateDisplay
, but also extract the TextFields
to instance variable and add them in an init
method. Values have to be set explicitly. You are expecting an implicit dataflow ... which is not given in ActionScript 3. The other way would be Events ... but that's just using methods as well.
At first, I'd create a dedicated event for notifications. This comes in handy as soon as you are more familiar with architectural ideas in ActionScript. This could be off course generalised, but for demonstration purposes of accessors (get score
) and mutators (set score
) perhaps a good idea.
package {
import flash.events.Event;
public class ScoreChangeEvent extends Event {
public static const SCORE_CHANGED:String = 'scoreChanged';
private var _score:int;
public function get score():int {
return _score;
}
public function ScoreChangeEvent(score:int) {
super(SCORE_CHANGED, true, false);
this._score = score;
}
override public function clone():Event {
return new ScoreChangeEvent(_score);
}
}
}
Then I refactored some portions of the code, making accessible what should be accessible, extensible what should be extensible and inaccessible, what should be not accessible by the outside world.
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
[Event(name="scoreChanged", type="ScoreChangeEvent")]
public class ScoreDisplay extends Sprite {
/** The text field displaying the score. */
protected var _scoreTextField:TextField;
/** The internal storage variable for score to display. */
private var _score:int;
/**
* The score to be displayed. When the score changes,
* a ScoreChangeEvent will be dispatched.
*
* @see ScoreChangeEvent#SCORE_CHANGED
*/
public function get score():int {
return _score;
}
public function set score(value:int):void {
if (_score == value) {
return;
}
_score = value;
updateDisplayList();
this.dispatchEvent(new ScoreChangeEvent(_score));
}
public function ScoreDisplay() {
init();
}
/** Creation of children and initial rendering. */
private function init():void {
this.createChildren();
this.updateDisplayList();
}
/**
* DisplayObjects, which are one created once should be
* created in a dedicated method.
*/
protected function createChildren():void {
if (!_scoreTextField) {
const format:TextFormat = new TextFormat();
format.size = 25;
format.font = "Verdana";
_scoreTextField = new TextField();
_scoreTextField.defaultTextFormat = format;
_scoreTextField.background = true;
_scoreTextField.autoSize;
_scoreTextField.width = 50;
_scoreTextField.height = 35;
_scoreTextField.x = 340;
_scoreTextField.y = 10;
_scoreTextField.mouseEnabled = false;
addChild(_scoreTextField);
}
}
/** Reset the display. */
public function reset():void {
this.score = 0;
}
/**
* Adds a certain value to the current score.
* @param value The calue to be added.
*/
public function addToScore(value:int):void {
score += value;
}
/**
* Update the display when ever needed.
*
* This method should never be triggered by an
* different class, only be the instance itself
* when a value changed.
*/
protected function updateDisplayList() {
this._scoreTextField.text = this.score.toString();
}
}
}
score
is only possible by the get/set methods, this makes it easy to understand when a value changed by logging or the debugger._scoreTextField
is protected, which means it may be modified by extending sub classes.addToScore
will modify the score
property which in return updates the display.updateDisplayList
will only be invoked when score
changed. This makes it easy to understand what's going on.My code is a cheap copy of the Flex component life cycle only to illustrate that there are certain patterns which may become pretty handy in 98% of all user interface related programming in Flash.
On the contrary, your class
could also simply be refactored to
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
public class ScoreDisplay extends Sprite {
protected var scoreTextField:TextField;
private var _score:int;
public function get score():int {
return _score;
}
public function set score(value:int):void {
if (_score == value) {
return;
}
_score = value;
scoreTextField.text = _score.toString();
}
public function ScoreDisplay() {
const format:TextFormat = new TextFormat();
format.size = 25;
format.font = "Verdana";
scoreTextField = new TextField();
scoreTextField.defaultTextFormat = format;
scoreTextField.background = true;
scoreTextField.autoSize;
scoreTextField.width = 50;
scoreTextField.height = 35;
scoreTextField.x = 340;
scoreTextField.y = 10;
scoreTextField.mouseEnabled = false;
addChild(scoreTextField);
}
public function addToScore(value:int):void {
score += value;
}
}
}
But that code is not really extensible and would require more change when the game gets more complex and what's more important, will require you to think a lot more when extending the component.
I hope that helped a bit.
Upvotes: 1