ActionScript 3 stage width - actionscript-3

Im doing my first flash AS game, so need a little help.
I have only 1 thing on the stage, its ball (layer instance) which has anchor point in the middle. I'm trying to make this ball bounce off walls (i mean screen).
This instance name is called 'kugla1'
Heres my code (its second frame):
if(kugla1.x<=kugla1.width/2 || kugla1.x>=stage.stageWidth-kugla1.width/2)
speedX=-speedX;
if(kugla1.y<=kugla1.height/2 || kugla1.height>=stage.stageHeight-kugla1.height/2)
speedY=-speedY;
kugla1.x+=speedX;
kugla1.y+=speedY;
First frame is:
var speedX:int=5;
var speedY:int=5;
kugla1.x=100;
kugla1.y=100;
And third frame is only:
gotoAndPlay(2);
what am I doing wrong?
Thanks!

Your problem, is likely this line:
if(kugla1.y<=kugla1.height/2 || kugla1.height>=stage.stageHeight-kugla1.height/2)
In the second part (after the ||) you are comparing the height of kugla1 instead of the y position.
Another issue you could run into, is your ball could potentially meet the same condition for longer than one frame, so it would be best to separate your speed from the current direction of movement.
See code comments:
On your first frame, you'll need two additional variables:
var speedX:int=5;
var speedY:int=5;
var curSpeedX:Number = speedX;
var curSpeedY:Number = speedY;
on your second frame:
if(kugla1.x <= kugla1.width/2){
curSpeedX = speedX; //we need the positive value to make it go right
}
if(kugla1.x >= stage.stageWidth - kugla1.width/2){
curSpeedX = -speedX; //we need the negative value to make it go left
}
if(kugla1.y <= kugla1.height/2){
curSpeedY = speedY; //we need the positive value to make it go down
}
if(kugla1.y >= stage.stageHeight - kugla1.height/2){
curSpeedY = -speedY; //we need the negative value to make it go up
}
kugla1.x+= curSpeedX;
kugla1.y+= curSpeedY;

Related

As3: Not move through objects? How is the logic behind this?

I have a function where I can control my character.
I also have a movieclip on the stage called assassin_table.
I want to make it so that the character can't move in the table, a.k.a make the table work like a wall.
I have this code:
if(!this.hitTestObject(_root.assassin_table))
{
if(upKeyDown)
{
gotoAndStop(4);
y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
x-=Math.sin(rotation/-180*Math.PI)*(mainSpeed +7);
}
if(!upKeyDown)
{
gotoAndStop(3);
}
}
However, if I touch the table, then I can't move at all.
I know it's because if(!this.hitTestObject(_root.assassin_table)), but I don't understand the logic behind NOT moving through objects. I'd much rather have a near pixel-perfect collision detection system, but since it's so hard to find any good info online which isn't confusing, I'll stick with hitTestObject for now :)
EDIT: Tried something, didn't really work that well.
if(!_root.assassinDead && !teleporting && this.currentFrame != 5)
{
if(this.hitbox.hitTestObject(_root.assassin_table))
{
_root.assassin_table.gotoAndStop(2);
if(this.x > _root.assassin_table.x)
{
trace("Can't move right");
canMoveRight = false;
}
if(this.x <_root.assassin_table.x)
{
trace("Can't move left");
canMoveLeft = false;
}
if(this.y > _root.assassin_table.y)
{
trace("Can't move up");
canMoveUp = false;
}
if(this.y < _root.assassin_table.y)
{
trace("Can't move down");
canMoveDown = false;
}
}
else
{
canMoveRight = true;
canMoveLeft = true;
canMoveUp = true;
canMoveDown = true;
}
}
This causes me to sometimes be able to walk through the table. I figure it's because my character can move in essentially every possible angle (since he's always facing the mouse and there are no tiles/grids).
How would I make it so that it would work with the advanced movement I have?
Moving up runs this:
y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
x-=Math.sin(rotation/-180*Math.PI)*(mainSpeed +7);
And the rotation is decided by this:
this.rotation = Math.atan2((stage.mouseY - this.y), (stage.mouseX - this.x)) * 180/ Math.PI + 90;
You should seperate your hittest functions for four different moving directions.
I mean, you shouldn't use this "hitTestObject" stuff, that only returns a boolean value "true" or "false", and that's not going to work for you.
You need a function like "testPoint(player.x, player.y);" and returns the object at the given position, so you can implement it for your game like that
if (upKeyDown && testPoint(player.x, player.y - mainSpeed +7) == null) y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
player.y - mainSpeed +7 // that checks for plus mainSpeed+7 because of trying to stop your player before it get stack inside object
Basically your logic flow should be like this:
Sample input (key press)
Move character
Check for collisions
If collision then move character to it's "outside" the object that it's touching
In your particular case, if your character is on the left of the table, and you're moving right, then first things first, you move your character. At your new position, check for any collisions. If you have a collection, then because you were moving from the left, we want to be on the left of the object that we colliding with, in this case the table, so we position our character to the left of the table.
The first part of that (checking if the character has hit the table) is called collision detection. Moving the character so that it's outside the bounds of the table is called collision response. Collision detection is a pretty big field and really depends on the type of game you're making; you can do grid-based, hit-test based (if you don't have a ton of objects), physics-based, math-based etc. Collision response can be anything and everything, depending on how you want to react to a collision - you can destroy the object (balloon on a spike), change its speed (character running through mud), bounce off it (ball off wall), or stop any further movement (character against wall).
To make things a bit easier:
Separate your systems - your input shouldn't be dependant on your collision for example. If the up key is down, just register that fact - what you do with it later (make your character move) is up to you
Separate your objects position in memory from its position on screen - this will let you move it around, react to collisions etc, and only when everything is good, update the graphics (stops things like graphics entering a wall only to jump out the next frame)
Solve for one axis at a time - e.g. collide on the x axis first, then the y
Pixel perfect collision is rarely needed :) Non-rotated boxes and circles will work a lot more than you'd think
Somewhat related - the shape of your object doesn't have to be the shape that you're colliding with - e.g. your table collision shape could just be a box; your character collision shape could just be a circle
Update
This causes me to sometimes be able to walk through the table
Assuming that we're going to collide our character and table as boxes, you need to take into account their sizes - i.e. we don't just compare the x values, but the right side of our character box against the left side of the table box etc. Something like:
// assumes objects have their anchor point in the top left - if its
// not the case, adjust as you see fit
if( char.x + char.width > table.x ) // right side of the char is overlapping the left side of the table
canMoveRight = false;
else if( char.x < table.x + table.width ) // left side of char vs right side of table
canMoveLeft = false;
// etc
When working with collisions, it's always nice to see the actual boxes, for debugging. Something like this:
var debug:Shape = new Shape;
debug.addEventListener( Event.ENTER_FRAME, function():void
{
debug.graphics.clear();
debug.graphics.lineStyle( 2.0, 0xff0000 );
// char (again assuming anchor point is top left)
debug.graphics.drawRect( char.x, char.y, char.width, char.height );
// table
debug.graphics.drawRect( table.x, table.y, table.width, table.height );
});
// add our debug. NOTE: make sure it's above everything
stage.addChild( debug );

AS3 create a trail of movieclips following each other

So, I'm trying to get a few movieclips to follow it's precursor and have the last one follow the mouse. The problem is I'm creating them from code instead of using the interface and, since I'm not an expert, I can't get them to work.
All I have in the library is a MovieClip(linkage:"LETRA") which contains a textField inside(instance name:"myTextField").
Here's what I have:
import flashx.textLayout.operations.MoveChildrenOperation;
import flash.display.MovieClip;
import flash.events.Event;
//this are the letters that will be following the mouse
var phrase:Array = ["H","a","c","e","r"," ","u","n"," ","p","u","e","n","t","e"];
//variable to spread them instead of creating them one of top of each other
var posXLetter:Number = 0;
//looping through my array
for (var i:Number = 0; i < phrase.length; i++)
{
//create an instance of the LETRA movieclip which contains a text field inside
var newLetter:MovieClip = new LETRA();
//assing a letter to that text field matching the position of the phrase array
newLetter.myTextField.text = phrase[i];
//assign X position to the letter I'm going to add
newLetter.x = posXLetter;
//add properties for storing the letter position
var distx:Number = 0;
var disty:Number = 0;
//add the listener and the function which will move each letter
newLetter.addEventListener(Event.ENTER_FRAME, moveLetter);
function moveLetter(e:Event){
distx = newLetter.x - mouseX;
disty = newLetter.y - mouseY;
newLetter.x -= distx / 10;
newLetter.y -= disty / 10;
}
//add each letter to the stage
stage.addChild(newLetter);
//increment the next letter's x position
posXLetter += 9;
}
With that code, only one letter is following the mouse (the "E") and the rest are staying where I added them using addChild and the posXLetter variable.
Also, I'm trying to get it to behave more like a trail, so if I move up, the letters will lag beneath me; if I move to the left, the letters will lag to my right but I think that with my current approach they will either A) move all together to the same spot or B) always hang to the left of the cursor.
Thanks for any possible help.
This is a kind of motion called Inverse Kinematics and it is a quite popular way to make rag dolls in games. It uses a design pattern called the Composite Pattern where one object adds another object as a child of its and then when it's update() function if called, it calls all of its (usually one) child's update() functions. The most common example of this is of a snake. The snake's head follows your mouse, and the rest of the snake's body pieces move with the snake, and it looks immensely realistic. This exact example is explained and build here although it does not include joint restrictions at all.
This example is in the middle of a book, and so may be hard to start reading, but if your somewhat familiar with design patterns and/or have some intermediate experience with programming, then i'm sure you can understand it. I advise that you, after reading and understanding the example, scratch what you have now because it is not very elegant coding. You may feel that this example uses too many classes, but trust me, its worth it as it allows you to very easily edit your code, if you decide to change it in the future, with no drawbacks.
Also, i know that this snake is not what you want, but if you understand the concept then you can apply it to your own specific needs.
I hope this helps.
I think it is a scoping issue. You might need to modify your handler
function moveLetter(e:Event){
trace(e.target); //check if this is the right movie clip
distx = e.target.x - mouseX;
disty = e.target.y - mouseY;
e.target.x -= distx / 10;
e.target.y -= disty / 10;
}

AS3 Clicking in "zones" of a picture

I have searched and simply cannot find what I need (if it exists).
A window will have a large picture.
The picture will be divided into zones (such as border lines that separate states on a map).
When a person clicks within a zone, then I will raise the appropriate event.
I've used AS3 with MXML to create a database program. All is working great except for this last step. I cannot figure out how the user is within a particular area of the picture when he clicks or when he touches.
I've read and tried to come up with an approach, and there must be (hopefully so) an easier way than the muddled nonsense I'm coming up with.
Thanks
VL
Are you drawing it in flash professional CS6? If so then why can't you just have the picture as a symbol and then just self divide the lines and make those divided areas into symbols that are children of the picture symbol. You could keep the individual state symbols right where they so that they stay true to the overall picture.
A first thought would be to make an instance of this picture symbol through the code, and then loop though all the children of that picture and add a click event to each one.
var picture:Picture=new Picture();
for(var i:int=0; i<picture.numChildren-1; i++){
picture.getChildAt(i).addEventListener(MouseEvent.CLICK, mouseEventHandler);
}
Please comment if I am missing something, or this does not work.
EDIT
Well, if you know the dimensions of the image, you could divide its width and height by 3(your number of rows and columns) and this is your zone dimensions. You then could take the mouse's click point relative to the top left of your picture and then divide its width by the zone with, and its height by the zone height, and then get its integer floor value, you could get which region it is. Code it below:
//This is all for a constat region list (like a window, or floor tiles, not things irregular)
import flash.display.Sprite;
var regionsX:int = 3; //Your number of windows across the row
var regionsY:int = 3; // across the column
var regions:Array = new Array(); // an array to hold the values that you will get from where the user clicks
// All of this used a 2D array method
for(var x:int = 0; x < regionX; x++) {
regions[regionsX] = new Array();
for(var y:int = 0; y < regionY; y++) {
regions[regionsX][regionsY] = "region(".concat(x).concat(",").concat(y);
// Here you make this equal to anything you want to get a value of,
//once the correct region is found (I just have a string version here for an example)
}
}
... // other stuff..
var picture:Picture = new Picture(); // your window picture
var regionWidth:Number = picture.width / regionsX; // Gets each region's width
var regionHeight:Number = picture.height / regionsY; // Get each regoin's height
...
picture.addEventListener(MouseEvent.CLICK, mouseEventListener); // add a click listener to the picture
function mouseEventListener(event:MouseEvent):void{
var mouseX:Number = picture.globalToLocal(event.stageX); // gets where the user clicked, and then converts it
//to the picture's cordinate space. ( 50,100 acording to the stage, could be (25,200) to the picture)
var mouseY:Number = picture.globalToLocal(event.stageY); // same for the Y
var regionIntX:Number = Math.floor(mouseX / regionWidth); // Dives the point by each region's width, and then
// converts it to a while integer. (For instance, if a region's width is 100 and you click at 288, then if you do the
// math, you clicked in the 3rd region, but it returns 2... why? (becaue the array counter starts at 0, so 0 is the 1st
// region, 1 is the second and so on...
var regionIntY:Number = Math.floor(mouseY / regionHeight); // Same for Y
var yourValue:String = regions[regionIntX][regionIntY]; // This returns that you initialy put into your 2d array
// by using the regionIntX and regionIntY for the array values. You have to decide what is stored in this array...
}
The simplest solution would be to add an event listener for MouseEvent.CLICK to the picture and in the handler check properties mouseX and mouseY of the picture. Define the bounds of each area in an XML or similar and check against current mouseX/Y to see which area has been clicked.

AS 3 simple ease

How can I move an object and be able to physically see it when it is moving? Not just disappear and appear on a different location like it would be using the following code.
buttonL2_btn.addEventListener(MouseEvent.CLICK, left);
function left(event:Event):void{
box_mc.x =241.5;
}
This is going to move myObject to any location specified, but again I want to be able to see it when moving.
In your example you are just setting it's X position when some button is pressed, when you need to change X into an EnterFrame event, like this:
this.addEventListener(Event.ENTER_FRAME, move);
function move(event:Event):void{
box_mc.x -= 5
}
Your box_mc should move left 5 pixels accordingly with your framerate.
You can use a easing library to that easily. I strongly recommend TweenMax.
Okay I am getting a bit sick of people constantly suggesting some tweening engine. Sure they rock, but it won't help the OP to understand what he is doing.
Kircho to move an object with a really easy tween I suggest the following code in an onEnterFrame event for your object to move:
addEventListener(Event.ENTER_FRAME, onEnterFrame);
var xGoal:Number = 100; //:: The target X destination for your object
var yGoal:Number = 100; //:: The target Y destination for your object
var smothness:Number = 10; //:: Smoothness factor for movement. The lower the value the faster the movement.
function onEnterFrame(e:Event):void
{
box_mc.x += (xGoal - box_mc.x) / smothness;
box_mc.y += (yGoal - box_mc.y) / smothness;
}
Will move/ease your box object to the desired location with a set smoothness.
You can install any of the 437 available tweening engines
or you can add a few lines of code
set up a variable that holds the destination value
var dest:Number = 241.5; // this is what gets updated on mouse click
on enterframe event for box:
function onBoxEnterFrame(e:MouseEvent):void{
if (dest != box_mc.x){
var easeNum:Number = 0.4 // between 0 and 1, the higher the number, the slower the transition
box_mc.x = box_mc.x * easeNum + dest * (1-easeNum);
}
}
you can add a few more lines to snap the position when it is close (less than 0.1 difference) or use a more linear change where you adjust incrementally like box_mc.x += 5; until it matches the dest number

Splicing elements out of a Vector in a loop which goes through the same Vector (ActionScript 3)

I'm making a simple game and have a Vector full of enemies in order to do hit-checking on them from my "laser" object (it's a space shmup). Every laser loops through the Vector and checks if it's occluding the hit circle. The problem lies in when one laser destroys an enemy, the rest of the lasers try to also check the same Vector, only to go out of bounds since the enemy's already been spliced out and it's changed the size of the Vector.
for each (var enemy:Enemy in enemies){
var distanceX = this.x - enemy.x;
var distanceY = this.y - enemy.y;
var distance = Math.sqrt( (distanceX*distanceX) + (distanceY*distanceY) );
if (distance <= enemy.hitRadius) {
enemy.removeEnemy();
enemies.splice(enemies.indexOf(enemy),enemies.indexOf(enemy));
}
}
How would I go about collecting the index of individual elements in the Vector to be deleted, then only deleting them when every Laser object is finished its checking?
edit: here's my removeEnemy() function from my Enemy class, just in case:
public function removeEnemy(){
removeEventListener(Event.ENTER_FRAME, move);
parent.removeChild(this);
trace("removed Enemy", enemies.indexOf(this));
}
edit edit: I'm also getting a null reference pointer error to "parent" in my removeEnemy() function... but only sometimes. I have a feeling that if I fix one of these two problems, the other will also be fixed but I'm not sure.
I fixed it! The problem was actually in how I used the "splice()" method. Turns out that the second parameter isn't the end index of where to stop splicing, it's the number of elements to be spliced. So when I was trying to splice element 0, I wasn't splicing anything, and when I was trying to splice element 3, I was also splicing 4 and 5. I feel like such a dunce for not reading the API right and wasting a couple hours on this. Thanks to everyone who commented-- you guys helped me rule out what I thought the problem was.