Context: For a legacy Flex/Actionscript drawing app, I need to add scaling of simple symbols. The app uses the Graffiti lib for drawing and the resulting shape data is stored as GraphicsPathCommands serialized to XML using the Degrafa lib for save and reload. I need to enable the user to scale these graphics and then get updated path data which can be serialized. The symbols are simple but more complicated than simple geometry. For example:
Question: I converted the SVG data for this symbol to Actionscript GraphicsPathCommands and am able to draw it, and of course translation is easy – but I don't know how I would scale it, given a bounding box defined by a user dragging out a marquee rectangle in the app.
Does anyone know of either an Actionscript way of transforming the command data, or a Javascript snippet for scaling SVG which I can port to Actionscript?
For reference, an example of the Actionscript GraphicsPathCommands for drawing a star is below.
public function DrawPathExample()
{
var star_commands:Vector.<int> = new Vector.<int>(5, true);
star_commands[0] = GraphicsPathCommand.MOVE_TO;
star_commands[1] = GraphicsPathCommand.LINE_TO;
star_commands[2] = GraphicsPathCommand.LINE_TO;
star_commands[3] = GraphicsPathCommand.LINE_TO;
star_commands[4] = GraphicsPathCommand.LINE_TO;
var star_coord:Vector.<Number> = new Vector.<Number>(10, true);
star_coord[0] = 66; //x
star_coord[1] = 10; //y
star_coord[2] = 23;
star_coord[3] = 127;
star_coord[4] = 122;
star_coord[5] = 50;
star_coord[6] = 10;
star_coord[7] = 49;
star_coord[8] = 109;
star_coord[9] = 127;
graphics.beginFill(0x003366);
graphics.drawPath(star_commands, star_coord);
}
Solution
A full solution for interactively scaling GraphicsPathCommand data is below. The path data was derived from an SVG put through this SVGParser. It generates path drawing commands in the form of graphics.lineTo(28.4,16.8);. A couple of utility functions separate the data from the commands and store them in Vectors so the data can be serialized. I don't need to use arbitrary SWGs so I just hardcoded the data.
package classes
{
import flash.display.GraphicsPathCommand;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
public class DrawSVG extends Sprite
{
private var startPt:Point = new Point();
private var selectRect:Rectangle = new Rectangle();
private var viewBox:Rectangle = new Rectangle();
protected var commands:Vector.<int> = new Vector.<int>();
protected var drawingData:Vector.<Number> = new Vector.<Number>();
protected var sourceDrawingData:Vector.<Number> = new Vector.<Number>();
public function DrawSVG()
{
super();
this.addEventListener(Event.ADDED_TO_STAGE, setup);
setupWomanData();
}
private function setup(event:Event):void
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(event:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
this.graphics.clear();
// offset so graphic draws centered on click point
startPt = new Point(event.stageX - (viewBox.width /2), event.stageY - (viewBox.height /2));
selectRect = new Rectangle(startPt.x, startPt.y, viewBox.width, viewBox.height);
var kx:Number = selectRect.width / (viewBox.width);
var ky:Number = selectRect.height / (viewBox.height);
var scaleFactor:Number = kx < ky ? kx : ky;
drawSymbol(scaleFactor);
this.graphics.lineStyle(1, 0x000000);
this.graphics.drawRect(selectRect.x, selectRect.y, selectRect.width, selectRect.height);
}
private function onMouseMove(event:MouseEvent):void
{
selectRect.width = Math.max(viewBox.width, Math.abs(event.stageX - startPt.x));
selectRect.height = Math.max(viewBox.height, Math.abs(event.stageY - startPt.y));
var kx:Number = selectRect.width / (viewBox.width);
var ky:Number = selectRect.height / (viewBox.height);
var scaleFactor:Number = kx < ky ? kx : ky;
this.graphics.clear();
drawSymbol(scaleFactor);
this.graphics.lineStyle(1, 0x000000);
this.graphics.drawRect(selectRect.x, selectRect.y, viewBox.width * scaleFactor, viewBox.height * scaleFactor);
}
private function onMouseUp(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
this.graphics.clear();
createSprite(commands, drawingData);
}
private function drawSymbol(toScale:Number):void
{
drawingData.length = 0;
for (var i:int = 0; i < sourceDrawingData.length; i++) {
drawingData[i] = Math.max(sourceDrawingData[i], sourceDrawingData[i] * toScale);
drawingData[i] += i % 2 == 0 ? startPt.x : startPt.y ;
}
this.graphics.clear();
this.graphics.lineStyle();
this.graphics.beginFill(0xff0000);
this.graphics.drawPath(commands, drawingData);
this.graphics.endFill();
}
private function createSprite(command:Vector.<int>, coord:Vector.<Number>):Shape{
var s:Shape = new Shape();
addChild(s);
s.graphics.beginFill(0xff);
s.graphics.drawPath(command, coord);
s.graphics.endFill();
return s;
}
private function setupWomanData():void
{
commands = new Vector.<int>();
drawingData = new Vector.<Number>();
viewBox= new Rectangle(0, 0, 24.629, 52.336);
addMoveToCmd(12.31,10.3);
addCurveToCmd(13.37,10.3,14.3,9.89);
addCurveToCmd(15.24,9.48,15.94,8.78);
addCurveToCmd(16.64,8.08,17.05,7.14);
addCurveToCmd(17.46,6.2,17.46,5.15);
addCurveToCmd(17.46,4.1,17.05,3.16);
addCurveToCmd(16.64,2.23,15.94,1.52);
addCurveToCmd(15.24,0.82,14.3,0.41);
addCurveToCmd(13.37,0,12.31,0);
addCurveToCmd(11.26,0,10.33,0.41);
addCurveToCmd(9.39,0.82,8.69,1.52);
addCurveToCmd(7.98,2.23,7.57,3.16);
addCurveToCmd(7.16,4.1,7.16,5.15);
addCurveToCmd(7.16,6.2,7.57,7.14);
addCurveToCmd(7.98,8.08,8.69,8.78);
addCurveToCmd(9.39,9.48,10.33,9.89);
addCurveToCmd(11.26,10.3,12.31,10.3);
addLineToCmd(12.314,10.304);
addMoveToCmd(24.6,26.36);
addLineToCmd(20.7,12.77);
addCurveToCmd(20.62,12.3,20.39,11.91);
addCurveToCmd(20.15,11.51,19.81,11.23);
addCurveToCmd(19.47,10.94,19.04,10.78);
addCurveToCmd(18.61,10.62,18.14,10.62);
addLineToCmd(6.49,10.62);
addCurveToCmd(6.02,10.62,5.59,10.78);
addCurveToCmd(5.16,10.94,4.82,11.23);
addCurveToCmd(4.48,11.51,4.24,11.91);
addCurveToCmd(4.01,12.3,3.93,12.77);
addLineToCmd(0.03,26.36);
addCurveToCmd(0.01,26.4,0.01,26.45);
addCurveToCmd(-0.01,26.5,-0.01,26.55);
addCurveToCmd(0.01,26.6,0.01,26.65);
addCurveToCmd(0.02,26.69,0.03,26.74);
addCurveToCmd(-0.15,27.95,0.55,28.69);
addCurveToCmd(1.25,29.44,2.2,29.6);
addCurveToCmd(3.15,29.77,4.05,29.3);
addCurveToCmd(4.95,28.84,5.17,27.63);
addLineToCmd(6.85,21.37);
addLineToCmd(4.07,34.88);
addCurveToCmd(3.81,35.51,3.91,36.15);
addCurveToCmd(4,36.78,4.35,37.3);
addCurveToCmd(4.7,37.81,5.26,38.13);
addCurveToCmd(5.81,38.45,6.49,38.45);
addLineToCmd(6.78,38.45);
addLineToCmd(6.78,49.72);
addCurveToCmd(6.78,50.99,7.59,51.62);
addCurveToCmd(8.41,52.25,9.39,52.25);
addCurveToCmd(10.37,52.25,11.19,51.62);
addCurveToCmd(12,50.99,12,49.72);
addLineToCmd(12,38.45);
addLineToCmd(12.63,38.45);
addLineToCmd(12.63,49.72);
addCurveToCmd(12.63,50.99,13.44,51.62);
addCurveToCmd(14.26,52.25,15.24,52.25);
addCurveToCmd(16.22,52.25,17.04,51.62);
addCurveToCmd(17.85,50.99,17.85,49.72);
addLineToCmd(17.85,38.45);
addLineToCmd(18.14,38.45);
addCurveToCmd(18.82,38.45,19.38,38.13);
addCurveToCmd(19.93,37.81,20.28,37.3);
addCurveToCmd(20.63,36.78,20.72,36.14);
addCurveToCmd(20.81,35.51,20.56,34.87);
addLineToCmd(17.78,21.37);
addLineToCmd(19.45,27.58);
addCurveToCmd(19.67,28.79,20.57,29.27);
addCurveToCmd(21.47,29.75,22.43,29.6);
addCurveToCmd(23.38,29.45,24.08,28.7);
addCurveToCmd(24.78,27.96,24.6,26.74);
addCurveToCmd(24.61,26.69,24.62,26.65);
addCurveToCmd(24.63,26.6,24.63,26.55);
addCurveToCmd(24.63,26.5,24.62,26.45);
addCurveToCmd(24.62,26.4,24.6,26.36);
addLineToCmd(24.601,26.356);
}
protected function addCurveToCmd(p1:Number, p2:Number, p3:Number, p4:Number):void
{
commands.push(GraphicsPathCommand.CURVE_TO);
sourceDrawingData.push(p1);
sourceDrawingData.push(p2);
sourceDrawingData.push(p3);
sourceDrawingData.push(p4);
}
protected function addMoveToCmd(p1:Number, p2:Number):void
{
commands.push(GraphicsPathCommand.MOVE_TO);
sourceDrawingData.push(p1);
sourceDrawingData.push(p2);
}
protected function addLineToCmd(p1:Number, p2:Number):void
{
commands.push(GraphicsPathCommand.LINE_TO);
sourceDrawingData.push(p1);
sourceDrawingData.push(p2);
}
}
}
Seems like there is a pretty straightforward way to do this. It looks like the only thing to scale are the coordinates themselves, so you may just apply a scale factor.
Based on your example:
public function ASEntryPoint() {
var star_commands:Vector.<int> = new Vector.<int>(5, true);
star_commands[0] = GraphicsPathCommand.MOVE_TO;
star_commands[1] = GraphicsPathCommand.LINE_TO;
star_commands[2] = GraphicsPathCommand.LINE_TO;
star_commands[3] = GraphicsPathCommand.LINE_TO;
star_commands[4] = GraphicsPathCommand.LINE_TO;
var star_coord:Vector.<Number> = new Vector.<Number>(10, true);
star_coord[0] = 66; //x
star_coord[1] = 10; //y
star_coord[2] = 23;
star_coord[3] = 127;
star_coord[4] = 122;
star_coord[5] = 50;
star_coord[6] = 10;
star_coord[7] = 49;
star_coord[8] = 109;
star_coord[9] = 127;
//reference shape to detect initial size
var s:Shape = shapeInRect(star_commands, star_coord);
var bounds:Rectangle = s.getBounds(s);
s.graphics.lineStyle(1);
s.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
addChild(s);
//fit to target
var targetSize:Rectangle = new Rectangle(150, 100, 75, 60);
//detect lesser factor - assuming you need to preserve proportions
var kx:Number = targetSize.width / (bounds.width);
var ky:Number = targetSize.height / (bounds.height);
var toUse:Number = kx < ky ? kx : ky;
//apply to coords
for (var i:int = 0; i < star_coord.length; i++) {
//size
star_coord[i] *= toUse;
//fix initial offset
star_coord[i] -= i % 2 == 0 ? bounds.x * toUse : bounds.y * toUse;
}
//draw
addChild(shapeInRect(star_commands, star_coord, targetSize));
}
private function shapeInRect(command:Vector.<int>, coord:Vector.<Number>, rect:Rectangle = null):Shape{
var s:Shape = new Shape();
addChild(s);
s.graphics.beginFill(0x003366);
s.graphics.drawPath(command, coord);
s.graphics.endFill();
if (rect){
s.graphics.lineStyle(1);
s.graphics.drawRect(0, 0, rect.width, rect.height);
s.x = rect.x;
s.y = rect.y;
}
return s;
}
Learning to code so this might sound noobish...
Using Action Script
I am trying to make my Agents react to my segments so they run away.
So I need to connect part of my Main code to my Agent code
Here is my code :
Main.as
package
{
import agent.Agent;
import flash.display.Sprite;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.geom.Point;
import flash.display.Stage;
public class Main extends Sprite
{
private var score:Score;
private var count:int;
private var bleh: int = 0;
private var Agents:Vector.<Agent>;
private var segments:Array;
private var numSegments:uint = 20;
private var player:Point = new Point (200, 200)
private var friend:Agent = new Agent;
private var snakeHead:SnakeHead;
private var snakeTail:SnakeTail;
private var background: Sprite;
private var border: Bushes;
private var xVel: Number;
private var yVel: Number;
public function Main():void
{
xVel = 0;
yVel = 0;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
snakeHead = new SnakeHead();
snakeTail = new SnakeTail();
score = new Score();
border = new Bushes;
score.x = 11;
score.y = 14;
addChild(score);
stage.addChild(border);
count = 0;
addChildAt(snakeHead,0);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
segments = new Array();
for(var i:uint = 0; i < numSegments; i++)
{
var segment:Segment = new Segment (10, 20);
addChildAt(segment,0);
addChildAt(snakeTail,0);
segments.push(segment);
}
//updatePoint();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// entry point
background = new LevelOne(); //creates the background
addChildAt(background,0);
Agents = new Vector.<Agent>();
addEventListener(Event.ENTER_FRAME, gameloop);
for (var x:int = 0; x < 3; x++)
{
var a:Agent = new Agent();
addChild(a);
Agents.push(a);
a.x = 400;
a.y = 300;
a.name = "Name"+x;
trace (x);
}
stage.addEventListener(MouseEvent.CLICK, createAgent);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
}
private function createAgent(e:MouseEvent):void
{
var a:Agent = new Agent();
addChild(a);
Agents.push(a);
a.x = mouseX;
a.y = mouseY;
}
private function gameloop(evt:Event):void
{
for (var i:int = 0; i < Agents.length; i++)
{
Agents[i].update();
if (snakeHead.hitTestObject(Agents[i]))
{
//trace (Agents[i].name);
removeAgent(Agents[i]);
Agents.splice(i,1);
count ++;
score.lowercasetext.text = count.toString();
trace("count: " + count);
}
}
}
private function onEnterFrame(evt:Event):void
{
player.x += xVel;
player.y += yVel;
drag(snakeHead, player.x, player.y);
drag(segments[0], snakeHead.x, snakeHead.y);
for(var i:uint = 1; i < numSegments; i++)
{
var segmentA:Segment = segments[i];
var segmentB:Segment = segments[i - 1];
drag(segmentA, segmentB.x, segmentB.y);
var PlayerHalfWidth: Number = segments[i].width / 2;
var PlayerHalfHeight: Number = segments[i].height / 2;
if (segments[i].x + PlayerHalfWidth > stage.stageWidth) {
segments[i].x = stage.stageWidth - PlayerHalfWidth;
} else if (segments[i].x - PlayerHalfWidth < 0) {
segments[i].x = 0 + PlayerHalfWidth;
}
if (segments[i].y + PlayerHalfHeight > stage.stageHeight) {
segments[i].y = stage.stageHeight - PlayerHalfHeight;
}else if (segments[i].y - PlayerHalfHeight < 0) {
segments[i].y = 0 + PlayerHalfHeight;
}
var playerHalfWidth: Number = segments[i - 1].width / 2;
var playerHalfHeight: Number = segments[i - 1].height / 2;
if (segments[i - 1].x + playerHalfWidth > stage.stageWidth) {
segments[i - 1].x = stage.stageWidth - playerHalfWidth;
} else if (segments[i - 1].x - playerHalfWidth < 0) {
segments[i - 1].x = 0 + playerHalfWidth;
}
if (segments[i - 1].y + playerHalfHeight > stage.stageHeight) {
segments[i - 1].y = stage.stageHeight - playerHalfHeight;
}else if (segments[i - 1].y - playerHalfHeight < 0) {
segments[i - 1].y = 0 + playerHalfHeight;
}
}
drag(snakeTail, segments[19].x, segments[19].y);
var HeadHalfWidth: Number = snakeHead.width / 2;
var HeadHalfHeight: Number = snakeHead.height / 2;
if (snakeHead.x + HeadHalfWidth > stage.stageWidth) {
snakeHead.x = stage.stageWidth - HeadHalfWidth;
} else if (snakeHead.x - HeadHalfWidth < 0) {
snakeHead.x = 0 + HeadHalfWidth;
}
if (snakeHead.y + HeadHalfHeight > stage.stageHeight) {
snakeHead.y = stage.stageHeight - HeadHalfHeight;
}else if (snakeHead.y - HeadHalfHeight < 0) {
snakeHead.y = 0 + HeadHalfHeight;
}
//drag(segments[19], snakeTail.x, snakeTail.y);
/*for each (var a: Agent in Agents) {
a.update();
trace ("Follow me on Twitter.");
if(segments[0].hitTestObject(a))
{
trace("True");
trace(bleh + " " + "F*CKING HELL!");
trace(a.name);
stage.removeChild(Agents[1]);
}
}*/
}
private function removeAgent(a:Agent):void
{
a.parent.removeChild(a);
trace("Collision Detected!");
}
private function keyDown (evt: KeyboardEvent): void {
//87=w 68=d 83=s 65=a
if (evt.keyCode == 87)
{
player;
yVel = -5;
}
if (evt.keyCode == 83)
{
player;
yVel = 5;
}
if (evt.keyCode == 68)
{
player;
xVel = 5;
}
if (evt.keyCode == 65)
{
player;
xVel = -5;
}
//trace (player.x + " " + player.y);
trace (xVel + " " + yVel);
}
private function keyUp (evt: KeyboardEvent): void {
//87=w 68=d 83=s 65=a
if (evt.keyCode == 87)
{
player;
yVel = 0;
}
else if (evt.keyCode == 83)
{
player;
yVel = 0;
}
else if (evt.keyCode == 68)
{
player;
xVel = 0;
}
else if (evt.keyCode == 65)
{
player;
xVel = 0;
}
}
private function drag(segment:MovieClip, xpos:Number, ypos:Number):void
{
var dx:Number = xpos - segment.x;
var dy:Number = ypos - segment.y;
var angle:Number = Math.atan2(dy, dx);
segment.rotation = angle * 180 / Math.PI;
var w:Number = segment.getPin().x - segment.x;
var h:Number = segment.getPin().y - segment.y;
segment.x = xpos - w;
segment.y = ypos - h;
}
}
}
Agent.as
package agent
{
import agent.states.ChaseState;
import agent.states.ConfusionState;
import agent.states.FleeState;
import agent.states.IAgentState;
import agent.states.IdleState;
import agent.states.WanderState;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.display.MovieClip;
import flash.events.*;
import Segment;
import Main;
public class Agent extends MovieClip
{
private var mouses:mouse;
public static const IDLE:IAgentState = new IdleState(); //Define possible states as static constants
public static const WANDER:IAgentState = new WanderState();
public static const CHASE:IAgentState = new ChaseState();
public static const FLEE:IAgentState = new FleeState();
public static const CONFUSED:IAgentState = new ConfusionState();
public var snake:Segment;
private const RAD_DEG:Number = 180 / Math.PI;
private var _previousState:IAgentState; //The previous executing state
private var _currentState:IAgentState; //The currently executing state
private var _pointer:Shape;
private var _tf:TextField;
public var velocity:Point = new Point();
public var speed:Number = 0;
public var fleeRadius:Number = 100; //If the mouse is "seen" within this radius, we want to flee
public var chaseRadius:Number = 50; //If the mouse is "seen" within this radius, we want to chase
public var numCycles:int = 0; //Number of updates that have executed for the current state. Timing utility.
public function Agent()
{
//Boring stuff here
_tf = new TextField();
_tf.defaultTextFormat = new TextFormat("_sans", 10);
_tf.autoSize = TextFieldAutoSize.LEFT;
_pointer = new Shape();
mouses = new mouse();
snake = new Segment(1, 1);
/*g.beginFill(0);
g.drawCircle(0, 0, 5);
g.endFill();
g.moveTo(0, -5);
g.beginFill(0);
g.lineTo(10, 0);
g.lineTo(0, 5);
g.endFill();*/
addChild(mouses);
addChild(_tf);
_currentState = IDLE; //Set the initial state
}
/**
* Outputs a line of text above the agent's head
* #param str
*/
public function say(str:String):void {
_tf.text = str;
_tf.y = -_tf.height - 2;
}
/**
* Trig utility methods
*/
public function get canSeeMouse():Boolean {
var dot:Number = snake.x * velocity.x + snake.y * velocity.y;
return dot > 0;
}
public function get distanceToMouse():Number {
var dx:Number = x - snake.x;
var dy:Number = y - snake.y;
return Math.sqrt(dx * dx + dy * dy);
}
public function randomDirection():void {
var a:Number = Math.random() * 6.28;
velocity.x = Math.cos(a);
velocity.y = Math.sin(a);
}
public function faceMouse(multiplier:Number = 1):void {
var dx:Number = snake.x - x;
var dy:Number = snake.y - y;
var rad:Number = Math.atan2(dy, dx);
velocity.x = multiplier*Math.cos(rad);
velocity.y = multiplier*Math.sin(rad);
}
/**
* Update the current state, then update the graphics
*/
public function update():void {
if (!_currentState) return; //If there's no behavior, we do nothing
numCycles++;
_currentState.update(this);
x += velocity.x*speed;
y += velocity.y*speed;
if (x + velocity.x > stage.stageWidth || x + velocity.x < 0) {
x = Math.max(0, Math.min(stage.stageWidth, x));
velocity.x *= -1;
}
if (y + velocity.y > stage.stageHeight || y + velocity.y < 0) {
y = Math.max(0, Math.min(stage.stageHeight, y));
velocity.y *= -1;
}
mouses.rotation = RAD_DEG * Math.atan2(velocity.y, velocity.x);
}
public function setState(newState:IAgentState):void {
if (_currentState == newState) return;
if (_currentState) {
_currentState.exit(this);
}
_previousState = _currentState;
_currentState = newState;
_currentState.enter(this);
numCycles = 0;
}
public function get previousState():IAgentState { return _previousState; }
public function get currentState():IAgentState { return _currentState; }
}
}
I am trying to develop a basic Snake game that involves some inverse kinematics and state machines. I'm trying to get it so when the first segment of the snake interacts with a certain "mouse", it disappears. However, when I do, it doesn't work and I end up getting ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
Here's my code:
package
{
import agent.Agent;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.geom.Point;
public class Main extends Sprite
{
private var Agents:Vector.<Agent>;
private var segments:Array;
private var numSegments:uint = 150;
private var player:Point = new Point (15, 15)
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
segments = new Array();
for(var i:uint = 0; i < numSegments; i++)
{
var segment:Segment = new Segment (5, 10);
addChild(segment);
segments.push(segment);
}
//updatePoint();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// entry point
graphics.beginFill(0xeeeeee);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
Agents = new Vector.<Agent>();
addEventListener(Event.ENTER_FRAME, gameloop);
for (var x:int = 0; x < 10; x++)
{
var a:Agent = new Agent();
addChild(a);
Agents.push(a);
a.x = Math.random() * 10;
a.y = Math.random() * 10;
}
stage.addEventListener(MouseEvent.CLICK, createAgent);
}
private function createAgent(e:MouseEvent):void
{
var a:Agent = new Agent();
stage.addChild(a);
Agents.push(a);
a.x = mouseX;
a.y = mouseY;
}
private function gameloop(e:Event):void
{
for each (var a: Agent in Agents) {
a.update();
trace ("Follow me on Twitter.");
for each(var target: Segment in segments)
{
if (target.hitTestPtarget.x, a.y + target.y, true))
{
stage.removeChild(a);
}
}
}
}
private function onEnterFrame(event:Event):void
{
drag(segments[0], player.x, player.y);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
for(var i:uint = 1; i < numSegments; i++)
{
var segmentA:Segment = segments[i];
var segmentB:Segment = segments[i - 1];
drag(segmentA, segmentB.x, segmentB.y);
}
}
private function keyDown (evt: KeyboardEvent): void {
//87=w 68=d 83=s 65=a
if (evt.keyCode == 87)
{
player.y-=50;
}
else if (evt.keyCode == 83)
{
player.y+=50;
}
else if (evt.keyCode == 68)
{
player.x+=50;
}
else if (evt.keyCode == 65)
{
player.x-=50;
}
trace (player.x + " " + player.y);
}
private function drag(segment:Segment, xpos:Number, ypos:Number):void
{
var dx:Number = xpos - segment.x;
var dy:Number = ypos - segment.y;
var angle:Number = Math.atan2(dy, dx);
segment.rotation = angle * 180 / Math.PI;
var w:Number = segment.getPin().x - segment.x;
var h:Number = segment.getPin().y - segment.y;
segment.x = xpos - w;
segment.y = ypos - h;
}
}
}
I have tried looking at other posts with the same topic, but I just don't understand what I'm doing wrong. Any help would be greatly appreciated!
You are adding Agents and Segments locally (in Main) and later you are trying to remove them from the stage (which is the top level of the swf and is an another display object).
Either do stage.addChild(...) in your init function or (this is a better option imo) replace stage.removeChild(...) with a removeChild(...) everywhere else - this will keep the objects in a local Main space (who knows, maybe you would want to move around your Main later, make everything invisible at once etc).
I'm trying to code a sort of strategy game through FlashDevelop and I'm getting problems when trying to use Events (particularly MouseEvents). It's not so much that the events are returning errors, it's just that they don't do anything, not even getting a trace.
I'm trying to make the hexagons HexObject image invisible when clicked on (just a simple test to see if the MouseEvent is actually working).
This is my code:
Main.as
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* ...
* #author Dean Sinclair
*/
public class Main extends Sprite {
public var gameInitialised:Boolean = false;
public var MIN_X:int = 0;
public var MAX_X:int = stage.stageWidth;
public var MIN_Y:int = 0;
public var MAX_Y:int = stage.stageHeight - 100;
public var GameGrid:HexGrid = new HexGrid(MIN_X, MAX_X, MIN_Y, MAX_Y);
public var blackBG:Shape = new Shape();
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(Event.ENTER_FRAME, update);
// entry point
}
private function update(event:Event):void {
if (gameInitialised == false) {
GameGrid.initialiseGrid();
initialiseBackground();
gameInitialised = true;
}
updateGraphics();
}
public function drawGrid():void {
for (var x:int = 0; x < GameGrid.TOTAL_X; x++) {
for (var y:int = GameGrid.yArray[x][0]; y < GameGrid.yArray[x][1]; y++) {
if (x != GameGrid.nox || y != GameGrid.noy) {
GameGrid.Grid[x][y].update();
this.stage.addChild(GameGrid.Grid[x][y].image);
}
}
}
}
public function updateGraphics():void {
this.stage.addChild(blackBG);
drawGrid();
}
public function initialiseBackground():void {
blackBG.graphics.beginFill(0x000000, 1);
blackBG.graphics.lineStyle(10, 0xffffff, 1);
blackBG.graphics.drawRect(0, 0, stage.stageWidth-1, stage.stageHeight-1);
blackBG.graphics.endFill();
}
}
}
HexGrid.as
package {
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* #author Dean Sinclair
*/
public class HexGrid extends Sprite {
public static var HEX_RADIUS:int = 0;
public static var HEX_DIAMETER:int = 0;
public static var GRID_WIDTH:int = 0;
public static var GRID_HEIGHT:int = 0;
public var TOTAL_X:int = 0;
public var MIN_X:int = 0;
public var MAX_X:int = 0;
public var MIN_Y:int = 0;
public var MAX_Y:int = 0;
public var Grid:Array;
public var yArray:Array;
public function HexGrid(min_x:int, max_x:int, min_y:int, max_y:int) {
super();
MIN_X = min_x;
MAX_X = max_x;
MIN_Y = min_y;
MAX_Y = max_y;
}
public function initialiseGrid():void {
setGridDetails();
setLineLengths();
setGridPositions();
}
public function setGridDetails():void {
HEX_RADIUS = 25;
HEX_DIAMETER = 2 * HEX_RADIUS;
GRID_WIDTH = (((MAX_X - MIN_X) / HEX_DIAMETER) - 1);
GRID_HEIGHT = ((((MAX_Y - 100) - MIN_Y) / (HEX_DIAMETER - (HEX_DIAMETER / 3))) - 3);
TOTAL_X = GRID_WIDTH + Math.floor((GRID_HEIGHT - 1) / 2);
}
private function setLineLengths():void {
yArray = new Array(TOTAL_X);
for (var a:int = 0; a < TOTAL_X; a++) {
yArray[a] = new Array(2);
}
for (var x:int = 0; x < TOTAL_X; x++) {
if (x < GRID_WIDTH) {
yArray[x][0] = 0;
}else {
yArray[x][0] = (x - GRID_WIDTH + 1) * 2;
}
yArray[x][1] = 1 + (2 * x);
if (yArray[x][1] > GRID_HEIGHT) {
yArray[x][1] = GRID_HEIGHT;
}
trace("Line", x, " starts at", yArray[x][0], " ends at", yArray[x][1]);
}
}
public var nox:int = 5;
public var noy:int = 3;
private function setGridPositions():void {
var hexState:int = 4;
Grid = new Array(TOTAL_X);
for (var x:int = 0; x < TOTAL_X; x++) {
Grid[x] = new Array(yArray[x][1]);
for (var y:int = yArray[x][0]; y < yArray[x][1]; y++) {
if(nox!=4 || noy!=6){
Grid[x][y] = new HexObject(HEX_DIAMETER + (HEX_DIAMETER * x) - (HEX_RADIUS * y), HEX_DIAMETER + (HEX_DIAMETER * y) - ((HEX_DIAMETER / 3) * y), HEX_RADIUS, 2);
}
}
}
}
}
}
HexObject.as
package {
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
/**
* ...
* #author Dean Sinclair
*/
public class HexObject extends Sprite {
[Embed(source = "../images/hexagons/hex_darkRed.png")]
private var DarkRedHex:Class;
[Embed(source = "../images/hexagons/hex_lightBlue.png")]
private var LightBlueHex:Class;
[Embed(source = "../images/hexagons/hex_midGreen.png")]
private var MidGreenHex:Class;
public var image:Bitmap = new LightBlueHex();
protected var state:int = 0;
private var radius:int = 0;
public function HexObject(xPos:int, yPos:int, hexRadius:int, hexState:int) {
super();
x = xPos;
y = yPos;
state = hexState;
radius = hexRadius;
checkState();
initialiseGraphics();
}
private function checkState():void {
switch(state) {
case 1: // plains
image = new MidGreenHex();
break;
case 2: // hills
break;
case 3: // rock
image = new DarkRedHex();
break;
case 4: // water
image = new LightBlueHex();
break;
default:
break;
}
}
private function initialiseGraphics():void {
image.visible = true;
image.width = radius * 2;
image.height = radius * 2;
image.x = x - radius;
image.y = y - radius;
}
private function onMouseClick(e:MouseEvent):void {
image.visible = false;
trace("image.visible =", image.visible);
}
public function update():void {
image.addEventListener(MouseEvent.CLICK, onMouseClick);
}
}
}
I've tried countless methods to get the events working, but none have had any success. Any sort of solution to this would be a lifesaver as I've been toiling over this for hours, thanks!
My problem was fixed by VBCPP, I was using the class Bitmap which cannot dispatch MouseEvents. The solution was to take image from HexObject and put it inside an container of type Sprite, with the logical one being the object it was in. I just had to add the following code inside HexObject.as:
this.addChild(image);
and then just refer to the Object in future as opposed to image.