Error: Call to a possibly undefined method crearNotaS through a reference with static type Class - actionscript-3

I'm new at programming and I'm working on a 'minigame' for my career.
I'm getting this error, hope someone can help me out.
public class Notas
{
public var stage:Stage;
public var velocidad:int = 5;
public var i:int = 0;
public var notaS:Array = new Array(16);
public var notaD:Array = new Array(16);
public function Notas(escenario:Stage)
{
stage = escenario;
}
public function Inicializar():void
{
crearNotaS(0xFFFFFF, 30, 10, 0, 0);
}
public function Destruir():void
{
if (notaS[i].y < 720)
{
for (i = 0; i < notaS.length; i++)
{
stage.removeChild(notaS[i])
}
}
}
public function Mover():void
{
notaS[i].y += velocidad;
}
public function drawRect(color:uint, ancho:int, alto:int, x:int, y:int):Sprite
{
var dj:Sprite = new Sprite();
dj.graphics.beginFill(color,1);
dj.graphics.drawRect(0,0,ancho,alto);
dj.graphics.endFill();
dj.x = x;
dj.y = y;
return(dj);
}
public function asignarNotas():void
{
notaS[0] = 1
}
public function crearNotaS(color:int, ancho:int, alto:int, x:int, y:int):void
{
var contador:int = 0;
for (i = 0; i < notaS.length; i++)
{
if (notaS[i] == 1 && i == 0)
{
notaS[i] = drawRect(color, ancho, alto, x, y);
stage.addChild(notaS[i]);
notaS[i].y = -alto / 2;
}
else if (notaS[i] == 1 && i > 0)
{
for (j = i; j < notaS.length; j++)
{
contador = i - j
notaS[i] = drawRect(color, ancho, alto, x, notaS[j].y + alto * contador);
stage.addChild(notaS[i]);
return;
}
}
}
}
}
Its supposed to create a array of squares (only if the content of the index is a 1, if it is a 0 then it won't create the square there.) one on top of each other and then move them all down, like a guitar hero.
Probably the way im doing it isn't proper but well, its the 1st thing i'm doing on my own...

ActionScript is an object oriented Language. Classes are supposed to be objects too and when you want to access their methods you either need to make an instance of them first or make sure the target function is of type "Static", which has limitations of its own.
This is all about core concepts which you need to know before running your code. I suggest taking a look at some tutorials about classes. This might be a good start:
Tutorial: Understanding Classes in AS3 Part 1
But about your code. It misses some imports and variable definitions, not a major flaw though. Im able to run your code. I will attach a zip file containing the AS3 AIR project which i created to test the code: Test Project
You could do this yourself in couple of steps:
Create an As3 project in the IDE of your choice. (I use FlashDevelop)
Declare the variable of type YourClass (Notas) which holds instance of your class
before using functions of your class make an instance of your class and store it in the variable.
viola, use public methods and properties of your class by accessing the variable you created.
this is the main function:
package
{
import flash.display.Sprite;
/**
* ...
* #author tkiafar
*/
public class Main extends Sprite
{
private var _not:Notas;
public function Main():void
{
if (stage) {
_not = new Notas(this.stage);
_not.asignarNotas();
_not.Inicializar();
}
}
}
}
this is your class that resides in the main package (beside main.as):
package
{
import flash.display.Sprite;
import flash.display.Stage;
public class Notas
{
public var stage:Stage;
public var velocidad:int = 5;
public var i:int = 0;
public var j:int = 0;
public var notaS:Array = new Array(16);
public var notaD:Array = new Array(16);
public function Notas(escenario:Stage)
{
stage = escenario;
}
public function Inicializar():void
{
crearNotaS(0xFF00FF, 30, 10, 0, 0);
}
public function Destruir():void
{
if (notaS[i].y < 720)
{
for (i = 0; i < notaS.length; i++)
{
stage.removeChild(notaS[i])
}
}
}
public function Mover():void
{
notaS[i].y += velocidad;
}
public function drawRect(color:uint, ancho:int, alto:int, x:int, y:int):Sprite
{
var dj:Sprite = new Sprite();
dj.graphics.beginFill(color, 1);
dj.graphics.drawRect(0, 0, ancho, alto);
dj.graphics.endFill();
dj.x = x;
dj.y = y;
return (dj);
}
public function asignarNotas():void
{
notaS[0] = 1
}
public function crearNotaS(color:int, ancho:int, alto:int, x:int, y:int):void
{
var contador:int = 0;
for (i = 0; i < notaS.length; i++)
{
if (notaS[i] == 1 && i == 0)
{
notaS[i] = drawRect(color, ancho, alto, x, y);
stage.addChild(notaS[i]);
notaS[i].y = -alto / 2;
}
else if (notaS[i] == 1 && i > 0)
{
for (j = i; j < notaS.length; j++)
{
contador = i - j
notaS[i] = drawRect(color, ancho, alto, x, notaS[j].y + alto * contador);
stage.addChild(notaS[i]);
return;
}
}
}
}
}
}
after all i have some suggestions:
seperate the array that contains control indexes and the one that contains sprites.
avoid making variables public. in your case there is no need for accessing them outside your class, but if you need to make them accessible, use getters/setters. google "getters/setters in as3".
invent some naming standards of your own. google "rules of naming in as3".

Related

ActionScript 3 - Error #1010: A term is undefined and has no properties

When testing my project, I got this error :
TypeError: Error #1010: A term is undefined and has no properties. firegame.as:115]
at firegame/checkhitammo()[..\Desktop\Flash\firegame.as:115
at firegame/mainloop()[..Desktop\Flash\firegame.as:77
I don't understand why and if I change the if statement to something simple it's all work fine.
This is my code :
package {
import flash.display.*;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
public class firegame extends MovieClip {
var tiger:Tiger = new Tiger();
var enemys:Array = new Array();
var scorea:Number = 0;
var ammoleft:Number = 0;
var ammo:Array = new Array();
var setint:Timer = new Timer(110);
var setenemy:Timer = new Timer(980);
var newenemy:Number;
var hitcheck:Array = new Array();
var totallength:Number;
public function firegame() {
startgame();
}
public function startgame() {
addplayer();
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveplayer);
stage.addEventListener(MouseEvent.MOUSE_DOWN, shotfire);
stage.addEventListener(MouseEvent.MOUSE_UP, shotfirestop);
setint.addEventListener(TimerEvent.TIMER, shotfirestart);
setenemy.addEventListener(TimerEvent.TIMER, addenemy);
stage.addEventListener(Event.ENTER_FRAME, mainloop);
setenemy.start();
}
public function addplayer():void {
tiger.y = 200;
tiger.x = 507;
addChild(tiger);
}
public function moveplayer(e:MouseEvent):void {
tiger.y = mouseY;
tiger.x = 507;
}
public function shotfire(e:MouseEvent):void {
setint.start();
}
public function shotfirestop(e:MouseEvent):void {
setint.stop();
}
public function shotfirestart(e:TimerEvent):void {
var fire:Fire = new Fire();
fire.x = 460;
fire.y = mouseY;
addChild(fire);
ammoleft -= 1;
ammo.push(fire);
}
public function addenemy(e:TimerEvent):void {
var enemy:Enemy = new Enemy();
enemy.x = 0;
enemy.y = Math.floor(Math.random() * (370 - 30) + 30);
addChild(enemy);
enemys.push(enemy);
}
public function mainloop(e:Event):void {
setscoreandammo();
moveammo();
moveenemy();
checkhitammo();
}
public function moveammo():void {
for (var i:int = 0; i < ammo.length; i++) {
ammo[i].x -= 15;
if (ammo[i].x < -30) {
removeChild(ammo[i]);
ammo[i] = null;
ammo.splice(i, 1);
}
}
}
public function moveenemy():void {
for (var b:int = 0; b < enemys.length; b++) {
enemys[b].x += 5;
if (enemys[b].x > 590) {
removeChild(enemys[b]);
enemys[b] = null;
enemys.splice(b, 1);
}
}
}
public function setscoreandammo():void {
score.text = String(scorea);
leftammo.text = String(ammoleft);
}
public function checkhitammo():void {
for (var i:int = ammo.length; i >= 0; i--) {
for (var b:int = enemys.length; b >= 0; b--) {
if (ammo[i].hitTestObject(enemys[b])) { // <--- this is the line where the error is fired
removeChild(ammo[i]);
ammo[i] = null;
ammo.splice(i, 1);
removeChild(enemys[b]);
enemys[b] = null;
enemys.splice(b, 1);
scorea += 50;
break;
}
}
}
}
}
}
Your specific problem is right here...
public function checkhitammo():void {
for (var i:int = ammo.length; i >= 0; i--) {
for (var b:int = enemys.length; b >= 0; b--) {
...you are starting the counters i and b with the length of the array, instead of the position of the last index. It should read...
public function checkhitammo():void {
for (var i:int = ammo.length - 1; i >= 0; i--) {
for (var b:int = enemys.length - 1; b >= 0; b--) {
That is, the length is 1-based, and positions are 0-based
first of all, all your for loops only has increment by 1 you may want to use like this
for (var i in ammo) {
for (var b in enemys) {
you just have to loop through array until something happens and break out of loop to make sure it doesn't check twice.
in this line
if (ammo[i].hitTestObject(enemys[b])) {
the error says program cannot find object in the array list, since it's just array it does not throw error like null pointer exception
if you swap ammo with enemys you will see that hitTestObject is trying to access a null object
and you don't really need to call this
ammo[i] = null;
since its already being removed

Actionscript 3.0 - MouseEvents not working

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.

Code for a 10x10 multiplication table in flash as3,

I'm new to coding in AS3, and I would like some assistance. I've recieved a task where I have to code a Multiplication table (10 rows, 10 columns). I've managed to code the table, but I need help to add the numbers needed without manually adding the text.
It should look somewhat like this;
Can someone here assist me with this task?
Here is my code:
var xColumns:uint=10;
var xRows:uint=10;
var _columnWidth:Number=40;
var _rowHeight:Number=40
var _width:Number=_columnWidth*xColumns;
var _height:Number=_rowHeight*xRows;
graphics.lineStyle(2, 0x0000ff, 1);
for(var i:int=1; i<=xColumns; i++){
graphics.moveTo(i*_columnWidth,0);
graphics.lineTo(i*_columnWidth,_height);
}
for(i=1; i<=xRows; i++){
graphics.moveTo(0,i*_rowHeight);
graphics.lineTo(_width,i*_rowHeight);
}
This is the sample of "Cell" class:
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
public class Cell extends Sprite
{
//---------------------------------------
protected var m_oLabel:TextField;
protected var m_nWidth:Number = 20;
protected var m_nHeight:Number = 20;
protected var _backgroundColor:Number;
//---------------------------------------
//Group: CONSTRUCTOR
public function Cell()
{
super();
m_oLabel = new TextField();
m_oLabel.text = "999";
m_oLabel.autoSize = TextFieldAutoSize.CENTER;
addChild(m_oLabel);
setLabel("999");
}
//--------------------------------------------------//
// PUBLIC PUBLIC PUBLIC PUBLIC //
//--------------------------------------------------//
public function setLabel(p_sLabel:String):void
{
m_oLabel.text = p_sLabel || "";
updateLayout();
}
public function get backgroundColor():Number
{
return _backgroundColor;
}
public function set backgroundColor(value:Number):void
{
_backgroundColor = value;
redraw();
}
//------------------- OVERRIDDEN -------------------//
override public function get width():Number
{
return m_nWidth;
}
override public function set width(value:Number):void
{
m_nWidth = value;
updateLayout();
redraw();
}
override public function get height():Number
{
return m_nHeight;
}
override public function set height(value:Number):void
{
m_nHeight = value;
updateLayout();
redraw();
}
//--------------------------------------------------//
// PRIVATE/PROTECTED PRIVATE/PROTECTED //
//--------------------------------------------------//
protected function updateLayout():void
{
//adjust layout
if (m_oLabel)
{
m_oLabel.x = width * .5 - m_oLabel.width * .5;
m_oLabel.y = height * .5 - m_oLabel.height * .5;
}
}
protected function redraw():void
{
var g:Graphics = this.graphics;
g.beginFill(_backgroundColor);
g.drawRect(0, 0, width, height);
g.endFill();
}
//------------------- OVERRIDDEN -------------------//
//--------------------------------------------------//
// EVENTS EVENTS EVENTS EVENTS //
//--------------------------------------------------//
//------------------- OVERRIDDEN -------------------//
//--------------------------------------------------//
// UTILS UTILS UTILS UTILS //
//--------------------------------------------------//
//------------------- OVERRIDDEN -------------------//
}
}
and usage:
var container:Sprite = new Sprite();
addChild(container);
container.x = 10;
container.y = 10;
for (var i:int = 0; i <= 10; i++)
{
for (var j:int = 0; j <= 10; j++)
{
var cell:Cell = new Cell();
if (i == 0 || j == 0)
{
//headers
cell.setLabel(Math.max(i, j).toString());
cell.backgroundColor = 0x808080;
}
else
{
var mul:Number = i * j;
cell.setLabel(mul.toString());
cell.backgroundColor = 0xC0C0C0;
}
container.addChild(cell);
cell.x = cell.width * j;
cell.y = cell.height * i;
}
}
which looks like this:
new class "Cell" gives you flexibility and encapsulation of code for creation of single table cell. In my example it is only container for textfield and has ability to draw background. I've created public methods/accessors that allow to modify the "features" of the cell (i.e. what is displayed in TextField and what is colour of background). I had to override default width/height behaviour as otherwise it would return the size of it's content which would vary depending on the TextField content and size and in table we need steady size.

how to make Astar pathfinding can used by multi enemy?

i have learn A star pathfinding from "AdvancED_ActionScript_Animation" e-book:
List item
i make node class, Node.as .
i make grid class, Grid.as .
i make AStar class, AStar.as .
and the main clas, Game.as .
A-star Pathfinding is work, but just 1 player.
how to make it work in multi player?
spoiler
4.Game.as :
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
public class Game extends Sprite
{
private var _cellSize:int = 30;
private var _grid:Grid;
private var _player:Sprite;
private var _index:int;
private var _path:Array;
public function Game()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
makePlayer();
makeGrid();
stage.addEventListener(MouseEvent.CLICK, onGridClick);
}
private function makePlayer():void
{
_player =new Sprite();
_player.graphics.beginFill(0x336633);
_player.graphics.drawCircle(0,0,5);
_player.graphics.endFill();
_player.x = Math.random() * 100;
_player.y = Math.random() * 100;
addChild(_player);
}
private function makeGrid():void
{
_grid = new Grid(10,10);
for (var i:int =0; i < 10; i++)
{
_grid.setWalkable(Math.floor(Math.random()*10),
Math.floor(Math.random()*10),false);
}
drawGrid();
}
private function drawGrid():void
{
graphics.clear();
for (var i:int =0; i < _grid.numCols; i++)
{
for (var j:int =0; j<_grid.numRows; j++)
{
var node:Node = _grid.getNode(i,j);
graphics.lineStyle(0);
graphics.beginFill(getColor(node));
graphics.drawRect(i *_cellSize,
j*_cellSize,_cellSize,
_cellSize);
}
}
}
private function getColor(node:Node):uint
{
if (! node.walkable)
{
return 0;
}
if (node == _grid.startNode)
{
return 0xcccccc;
}
if (node == _grid.endNode)
{
return 0xcccccc;
}
return 0xffffff;
}
private function onGridClick(event:MouseEvent):void
{
var xpos:int =Math.floor(mouseX/_cellSize);
var ypos:int =Math.floor(mouseY/_cellSize);
_grid.setEndNode(xpos,ypos);
xpos = Math.floor(_player.x / _cellSize);
ypos = Math.floor(_player.y / _cellSize);
_grid.setStartNode(xpos,ypos);
drawGrid();
findPath();
}
private function findPath():void
{
var astar:AStar = new AStar();
if (astar.findPath(_grid))
{
_path = astar.path;
_index = 0;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
private function onEnterFrame(event:Event):void
{
var targetX:Number = _path[_index].x * _cellSize
+ _cellSize / 2;
var targetY:Number = _path[_index].y * _cellSize
+ _cellSize / 2;
var dx:Number = targetX - _player.x;
var dy:Number = targetY - _player.y;
var dx2:Number = targetX - _box.x;
var dy2:Number = targetY - _box.y;
var dist2:Number =Math.sqrt(dx2*dx2+dy2+dy2);
var dist:Number =Math.sqrt(dx*dx+dy+dy);
if (dist<1)
{
_index++;
if (_index >= _path.length)
{
removeEventListener(Event.ENTER_FRAME,onEnterFrame);
}
}
else
{
_player.x += dx * .5;
_player.y += dy * .5;
}
}
}
}
I am not going to go the extra mile and code this for you. (Anyone else can feel free to do that)
What you need to do is create a function that accepts a start node and end node, and returns the path. Something like this :
public function getPath(starNode:Point, endNode:Point):Array
{
// get your path by utilizing the astar instance
// return that path array
// note that I have used Points to store the x,y location
// you'll need to apply those values to the grid before your astar call
// using the setStarNode and setEndNode methods of the grid instance
}
Then you can modify the code that is used in your enterFrame, to utilize an array containing path data for any player/enemy you want.
For example you might have a function you call for each entity such as :
public function followPath(entity:MovieClip, pathData:Array, pathIndex:int):void
{
// your modified code from onEnterFrame
// replace _player variable with entity
// replace _path variable with pathData
// replace _index with pathIndex
}
If you understand OOP well enough, you might want to create a class for your player/enemy entities that has properties for pathData and pathIndex. If you do that, than you can just call an update method that will update their movement each frame using the pathData and pathIndex properties of that instance.
This is a basic approach you could use to accomplish your goal.

Collision detection for loop problem, only one array item tested?

[I apologise if this isn't really an in depth question, but I wanted to solve this once and for all]
I was trying to get look into quadtrees, but already ran into trouble getting collision detection without any optimization working properly. Did a search and found a pretty neat example:
http://wonderfl.net/c/kyLx
(onenterframeC part mostly)
Trying to imitate this, it won't work the same.
Only some collisions are detected between particular objects. When the objects are not moving it seems to work alot better for some reason.
I really can't figure out whats the problem, the code is essentially the same as the sample. I did not blindy copy pasted it, I understands whats happening except for this part:
if (j <= i)
continue;
J would never become bigger that I right? The line also completely removes any working collisions for me.
Here is what I did:
[view result here: http://martinowullems.com/collision.swf
Main class
package
{
import com.martino.objects.Square;
import com.martino.world.TestWorld;
import flash.display.MovieClip;
import flash.events.Event;
import net.hires.debug.Stats;
/**
* ...
* #author Martino Wullems
*/
public class CollisionTest extends MovieClip
{
var world:TestWorld;
public function CollisionTest()
{
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
SetupWorld();
addChild(new Stats());
}
private function SetupWorld():void
{
world = new TestWorld();
addChild(world);
addObjects(50);
}
private function addObjects(amount:int):void
{
for (var i:int = 0; i < amount; ++i) {
var square:Square = new Square(14);
world.addObject(square);
square.x = Math.random() * stage.stageWidth;
square.y = Math.random() * stage.stageHeight;
square.speedX = (Math.random() * 1) + 1;
square.speedY = (Math.random() * 1) + 1;
}
}
}
}
TestWorld
package com.martino.world
{
import com.martino.objects.Ball;
import com.martino.objects.CollisionObject;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* #author Martino Wullems
*/
public class TestWorld extends MovieClip
{
public var objects:Array;
public function TestWorld()
{
initWorld();
}
private function initWorld():void
{
objects = new Array();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function loopWorld(e:Event):void
{
for (var i:int = 0; i < objects.length; i++) {
MoveObject(objects[i]);
CheckCollision(i, objects[i]);
}
}
private function CheckCollision(i:int, object:CollisionObject):void
{
//for (var j:int = i + 1; i < objects.length; j++) {
for (var j:int = 0; j < objects.length; j++) {
//if (j <= i)
//continue;
var objectB:CollisionObject = objects[j];
//hittest
if (object.hitTestObject(objectB)) {
object.isHit = true;
objectB.isHit = true;
}else {
object.isHit = false;
objectB.isHit = false;
}
/////////////////
// CHECK X Y //
////////////////
/*if (object.x + object.width < objectB.x) {
} else if (object.x > objectB.x + objectB.width) {
object.isHit = objectB.isHit = false;
} else if (object.y + object.height < objectB.y) {
object.isHit = objectB.isHit = false;
} else if (object.y > objectB.y + objectB.height) {
object.isHit = objectB.isHit = false;
} else {
object.isHit = objectB.isHit = true;
}*/
object.debugDraw();
objectB.debugDraw();
}
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.speedX;
object.y += object.speedY;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.speedX *= -1;
}else if (object.x < 0)
{
object.speedX *= -1;
}else if (object.y > stage.stageHeight)
{
object.speedY *= -1;
}else if (object.y < 0)
{
object.speedY *= -1;
}
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
}
}
}
CollisionObject
package com.martino.objects
{
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* ...
* #author Martino Wullems
*/
public class CollisionObject extends Sprite
{
public var size:int;
public var speedX:int = 0;
public var speedY:int = 0;
public var graphic:Sprite;
var sleeping:Boolean = false;
public var isHit:Boolean = false;
public function CollisionObject()
{
addEventListener(MouseEvent.MOUSE_DOWN, grab);
addEventListener(MouseEvent.MOUSE_UP, letGo);
}
private function grab(e:MouseEvent):void
{
startDrag();
speedX = 0;
speedY = 0;
}
private function letGo(e:MouseEvent):void
{
stopDrag();
}
public function Collision():void{
}
//////////////////////
// setter and getter//
//////////////////////
public function set isHit(value:Boolean):void {
_isHit = value;
graphic.visible = _isHit;
hitGraphic.visible = !_isHit;
}
public function get isHit():Boolean {
return _isHit;
}
}
}
Square
package com.martino.objects
{
import flash.display.Sprite;
/**
* ...
* #author Martino Wullems
*/
public class Square extends CollisionObject
{
public var hitGraphic:Sprite;
public function Square(Size:int)
{
size = Size;
drawSquare();
}
private function drawSquare():void
{
graphic = new Sprite();
graphic.graphics.beginFill(0xFF0000);
graphic.graphics.drawRect(0, 0, size, size);
graphic.graphics.endFill();
addChild(graphic);
hitGraphic = new Sprite();
hitGraphic.graphics.beginFill(0x0066FF);
hitGraphic.graphics.drawRect(0, 0, size, size);
hitGraphic.graphics.endFill();
addChild(hitGraphic);
hitGraphic.visible = false;
}
override public function Collision():void {
trace("I collided with a friend (inside joke)");
}
public override function debugDraw():void {
if (isHit) {
graphic.visible = false;
hitGraphic.visible = true;
}else {
graphic.visible = true;
hitGraphic.visible = false;
}
}
}
}
Any help would greatly be appreciated, want to get further on this !
EDIT: Changed some stuff, there is progress but stuff still is unclear to me !
Changed some things in TestWorld.as:
package com.martino.world
{
import com.martino.objects.Ball;
import com.martino.objects.CollisionObject;
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* #author Martino Wullems
*/
public class TestWorld extends MovieClip
{
public var objects:Array;
public function TestWorld()
{
initWorld();
}
private function initWorld():void
{
objects = new Array();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function loopWorld(e:Event):void
{
var object:*;
for (var i:int = 0; i < objects.length; i++) {
MoveObject(objects[i]);
//CheckCollision(i);// doesn't work here for some reason [case 1]
}
CheckCollision(0); //[case 2]
}
private function CheckCollision(i:int):void
{
//test collision
for (var i:int = 0; i < objects.length; i++){ //only use in case 2
var elementA:CollisionObject;
var elementB:CollisionObject;
elementA = objects[i];
for (var j:int = i + 1; j < objects.length; j++) {
if (j <= i){
continue; //j resets each I loop and therefor sets collision to false while it could be true
}
elementB = objects[ j ]// as ObjSprite;
if (elementA.hitTestObject(elementB)) {
elementA.isHit = elementB.isHit = true;
}
}
} //[case 2]
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.vx;
object.y += object.vy;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.vx *= -1;
}else if (object.x < 0)
{
object.vx *= -1;
}else if (object.y > stage.stageHeight)
{
object.vy *= -1;
}else if (object.y < 0)
{
object.vy *= -1;
}
object.isHit = false;// where do we check when it isn't colliding? this seems messy!
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
}
}
}
Also added a setter and getter in collisionobject (so section before the edit).
Not sure why I can't put the checkcollision inside the loop on the enter frame function? (when I do no collisions are shown). And placing "isHit = false" inside moveobjects to reset a check for a hit also seems pretty messy.
I can't seem to find out when the objects aren't colliding to reset them I guess.
Making an else statement on the hittest to check if there is no collision doesn't work, seems logical since there could be collisions with more than just 2 items in the hittestcheck.
Any idea's ?
I had to look at the original source to understand this. It is below, for reference.
This line
if (j <= i) continue;
is a permutation check; it basically makes sure that each combination only gets checked once, instead of multiple times. However, for this, you need to have two For loops - an inner one and an outer one.
You've done the same thing with the following line:
for (var j:int = i + 1; i < objects.length; j++) {
Try using that for loop instead of the one that starts from zero. Leave the "if j <= i" line commented, though. I think that will solve your problem. (Those two statements can't coexist in this loop; if used together, they'll cause the problems you're describing.)
Good luck.
Original source from website:
for (i = 0; i < myrects.length; i++) {
elementA = myrects[ i ] as ObjMyRect;
for (j = 0; j < myrects.length; j++) {
if (j <= i)
continue;
elementB = myrects[ j ] as ObjMyRect;
if (elementA.rect.x + elementA.rect.width < elementB.rect.x) {
} else if (elementA.rect.x > elementB.rect.x + elementB.rect.width) {
} else if (elementA.rect.y + elementA.rect.height < elementB.rect.y) {
} else if (elementA.rect.y > elementB.rect.y + elementB.rect.height) {
} else {
elementA.isHit = elementB.isHit = true;
}
}
}
(For what it's worth, I think that this guy's code actually checks objects against themselves for collision - he should change the "if j <= i" line to "if j < i". You solved this problem with your original for loop.)
Couple of things, after looking at his code, and reviewing your code.
This part IS necessary to make sure you don't waste time going through the loop and re-checking items that have already been compared.
if (j <= i)
continue;
Imagine you have 3 items in the array, and compare item 3 to item 0. Then you compare item 3 to item 1, and item 3, to item 2. THEN you compare item 2 to... item 3? You've already done that. You want to compare item 2 to anything lesser than itself so you avoid duplicates.
Your code is close to his, but you've swapped out his version of the hitTest (which uses position + dimension) with the already-defined hitTestObject. I'm only seeing one hit-test on the first square. Something seems off in that... I'd drop some trace statements in there and see what's up.
Last, when you uncomment his code, does it work?