Dual fire and positioning problems - actionscript-3

I'm working on a space shooter and have this problem:
My space ship fires bullets. The bullets are centered in reference to the ship. Currently all bullets are single shots.
Now what I'd like to have is dual fire for the ship. Basically that means I have to double the shots and place them at the left and right
side of the ship, right? But I don't know how to do it exactly.
The other problem I have is that when I change the x and y-coordinates of the bullet in order to move the bullets from the center of the ship to the left (or right) and rotate the ship and fire I get a strange behavior of the bullets. In this case they move from the left to the center and vice versa referring to the ship (while rotating and firing).
Please - has anyone any idea where the problems might be and how to do it? I appreciate very much any help. TIA!:)
private function autoShoot(step:Number):void {
projectileManager.projectilePoolCount = projectileManager.projectilePool.length - 1;
asteroidManager.asteroidCount = asteroidManager.asteroids.length;
if (projectileManager.lastProjectileShot > projectileOffset && projectileManager.projectilePoolCount > 0 &&
playerStarted && asteroidManager.asteroidCount > 0 && projNumber < projectileNumber)
{
dispatchEvent(new CustomEventSound(CustomEventSound.PLAY_SOUND, Main.SOUND_PLAYER_SHOOT,
false, 0, 8, 1));
tempProjectile = projectileManager.projectilePool.pop();
tempProjectile.projectileDelayCount = 0;
var projectileRadians:Number = (player.frame / 360) * 6.28;
projShots++;
projNumber++;
if (projNumber >= projectileNumber)
{
player.startDelay = true;
}
tempProjectile.x = (player.point.x) + Math.cos(projectileRadians);
tempProjectile.y = (player.point.y) + Math.sin(projectileRadians);
tempProjectile.x = player.x + 13;
tempProjectile.y = player.y + 13;
tempProjectile.nextX = tempProjectile.x;
tempProjectile.nextY = tempProjectile.y;
tempProjectile.dx = rotationVectorList[player.frame].x;
tempProjectile.dy = rotationVectorList[player.frame].y;
tempProjectile.speed = projectileSpeed;
tempProjectile.frame = 0;
tempProjectile.bitmapData = tempProjectile.animationList[0];
tempProjectile.projectileDelay = 10;
projectileManager.projectiles.push(tempProjectile);
projectileManager.lastProjectileShot = 0;
} else {
projectileManager.lastProjectileShot += step;
}
}

The autoShoot function only fires one projectile each time it is called. There is only one tempProjectile per call to push to the projectiles list.
So one fix can be to add a tempProjectile2 (in the same place tempProjectile is defined) as a variable that can be used. Now in each call the projectile pool gets depleted by two, as long an adequate number of projectiles are popped
tempProjectile = projectileManager.projectilePool.pop();
tempProjectile2 = projectileManager.projectilePool.pop();
then adjust the offset accordingly
tempProjectile.x
tempProjectile.y
tempProjectile2.x
tempProjectile2.y
And so on with the rest of the code. The only thing I am unclear about is why tempProjectile.x and y are assigned twice.
tempProjectile.x = (player.point.x) + Math.cos(projectileRadians);
tempProjectile.y = (player.point.y) + Math.sin(projectileRadians);
tempProjectile.x = player.x + 13;
tempProjectile.y = player.y + 13;
only the second pair will be used, I think.
Hopefully the rest of the functions should not change because at the end the projectiles are pushed to the projectiles list
projectileManager.projectiles.push(tempProjectile);
projectileManager.projectiles.push(tempProjectile2);
So the whatever function used to update and render should remain the same, assuming tempProjectile is not tied down elsewhere in the program.

Related

Pairing a draggable object to a target object in AS3

I'm currently stuck with my approach below. I'm not entirely sure if using "hitTestObject" method is appropriate in pairing the pieces to their respective place. I was able to at least match the chess piece to their respective location (that's the best I can do and I feel i'm doing it wrong) but I'm now stuck in counting how many pieces are actually in their correct places. e.g. when I move the pawn to a different tile, it will still count as one, I also want to avoid duplicate counting, example, If pawn is already in the correct location, it will just count as 1, and if it was moved, then that count will be removed. Only count the pieces that are in the correct tile.
My goal here is to be able to make all the chess pieces draggable and determine if they're in their respective location. If ALL the chess pieces are in their location, it will trace or call a function.
Thank you!
import flash.events.Event;
import flash.display.MovieClip;
import flash.events.MouseEvent;
/* Declaring an X and Y variable to be used as a reset container */
var xPos: int, yPos: int;
/* Attaching event listeners for each chess piece */
addListeners(
king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8);
/* Getting the original x and y postion to be used as a reset */
function getPosition(currentTarget: Object): void {
xPos = currentTarget.x;
yPos = currentTarget.y;
}
/* Function to get the suffix value of an object. example, I need to get the value 4 from "pawn_4" */
function getLastCharInString($s: String, $pos: Number): String {
return $s.substr($s.length - $pos, $s.length);
}
/* A simple function that rotates the chess piece */
function lift(object: Object, rot: Number) {
object.rotation = rot;
}
function dragObject(e: MouseEvent): void {
getPosition(e.currentTarget);
lift(e.currentTarget, -10);
getChildByName(e.currentTarget.name + "_hs").alpha = 1;
e.currentTarget.startDrag();
}
/* This variable is supposed to hold the value of each piece that is correctly placed in each tile.
The total score should be 16 as there are 16 pieces. Only correcly placed piece should be added in the total score. */
var counter:int;
function stopDragObject(e: MouseEvent): void {
var curretTarget = e.currentTarget.name;
lift(e.currentTarget, 0);
/* Hide active hotspots */
getChildByName(e.currentTarget.name + "_hs").alpha = 0;
var multiplePieceSufix = Number(getLastCharInString(curretTarget, 1));
if (multiplePieceSufix >= 1) {
/* Boolean variables that checks whether the current piece is active*/
var isPawn: Boolean = false,
isBishop: Boolean = false,
isKnight: Boolean = false,
isRook: Boolean = false,
currentTargeName;
var widthDiff = getChildByName(e.currentTarget.name + "_hs").width - getChildByName(e.currentTarget.name).width / 2;
var heightDiff = getChildByName(e.currentTarget.name + "_hs").height - getChildByName(e.currentTarget.name).height / 2;
if (curretTarget.substr(0, 4) == "pawn") {
isPawn = true;
} else if (curretTarget.substr(0, 6) == "bishop") {
isBishop = true;
} else if (curretTarget.substr(0, 6) == "knight") {
isKnight = true;
} else if (curretTarget.substr(0, 4) == "rook") {
isRook = true;
}
if (isPawn == true) {
/* there are total of 8 pieces of pawn */
for (var w = 1; w < 9; w++) {
currentTargeName = this["pawn_" + w + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
/* For some reason the chess pieces are not aligning with their "_hs" version, I already checked their registry point and it seem to be normal.
so to fix, I had to manually add some hard coded values to adjust their location. */
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}
}
} else if (isBishop == true) {
for (var x = 1; x < 3; x++) {
currentTargeName = this["bishop_" + x + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 9;
e.currentTarget.y = currentTargeName.y + currentTargeName.height - 18;
}
}
} else if (isKnight == true) {
for (var y = 1; y < 3; y++) {
currentTargeName = this["knight_" + y + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}
}
} else if (isRook == true) {
for (var z = 1; z < 3; z++) {
currentTargeName = this["rook_" + z + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + 62;
}
}
}
} else {
if (e.target.hitTestObject(getChildByName(e.currentTarget.name + "_hs"))) {
/* Again, I'm not sure why the pieces are not aligning as intended.
modX and modY is a holder for the adjustment value. I'm not comfortable
seeing this approach myself, but I also run out of ideas how to fix it. */
var modX: Number, modY: Number;
if (e.currentTarget.name == "king") {
modX = 11;
modY = 53;
} else {
modX = 11;
modY = 29;
}
e.currentTarget.x = getChildByName(e.currentTarget.name + "_hs").x - modX;
e.currentTarget.y = getChildByName(e.currentTarget.name + "_hs").y + getChildByName(e.currentTarget.name + "_hs").height - modY;
}
}
/* This is supposed to add to the total score or count of how many pieces are placed correctly.
Thie problem with thi scounter, as it also counts any piece that is places to any "_hs" */
counter++;
trace(counter);
e.currentTarget.stopDrag();
}
function addListeners(...objects): void {
for (var i: int = 0; i < objects.length; i++) {
objects[i].addEventListener(MouseEvent.MOUSE_DOWN, dragObject);
objects[i].addEventListener(MouseEvent.MOUSE_UP, stopDragObject);
// hide hotspots
getChildByName( objects[i].name + "_hs" ).alpha = 0;
}
}
Source: Download the FLA here
--
Updates:
I have added comments in my code to clarify what I'm trying to accomplish.
I'm planning to do board game in flash which has similar function and behaviour to this. User can drag the object to a specified tile and check wether that object belongs there or not.
After reviewing your code, your question is quite broad. I'm going pair it down to what seems to be your main concern - the score / counting correctly moved pieces.
Right now, you do the following every time an object is dragged:
counter++;
This means that the counter will increment no matter where you drag the object, and no matter how times you drag the object. (so even if the piece was already in the correct spot, if you dragged it a second time it will still increment your counter).
What you need to do, is associate a flag with each object to indicate whether it is in the correct location or not, and set that flag to the appropriate value every time that object is done dragging.
Something like this:
//don't use target, use currentTarget
if (e.currentTarget.hitTestObject(currentTargeName)) {
e.currentTarget.correct = true; //since MovieClips are dynamic, you can just make up a property on them and assign a value to it.
//to fix your alignment:
e.currentTarget.x = currentTargeName.x + ((currentTargetName.width - e.currentTarget.width) * 0.5);
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}else{
//if the hit test is false, mark it as NOT correct
e.currentTarget.correct = false;
}
Then, later to know the current count, iterate over all the pieces and check their correct value. This would be much easier if all your pieces were in an array.
var allPieces:Array = [king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8];
function countCorrect():Boolean {
var ctr:int = 0;
for(var i:int=0;i<allPieces.length;i++){
if(allPieces[i].correct) ctr++;
}
return ctr;
}
trace(countCorrect() + " of " allPieces.length " are correct");
As an aside, this best way to do this would be with some custom class files. That would however require a complete refactoring of your code.
Also, you probably don't want to use hitTestObject, as even if a piece is mostly over a neighbor, it will still be true as long as 1 pixel of it's bound touch 1 pixel of the tile. Better would be to do a hitTestPoint on the tile, and pass in the center point of the piece (the the middle of the piece has to be touching the tile for it to count).
//a point that is the center of the events current target (the piece)
var point:Point = new Point();
point.x = e.currentTarget.x + (e.currentTarget.width * 0.5);
point.y = e.currentTarget.y - (e.currentTarget.height * 0.5);
if (currentTargetName.hitTestPoint(point)) {

Resetting a players x position (Flash As3)

private function scrollStage():void
{
if (lastPosX != lastPosX)
{
canScrollStage = false;
}
else
if (lastPosX == lastPosX)
{
canScrollStage = true;
}
if (canScrollStage)
{
if (rightKey)
{
//move background left
//something.x +=(stage.stageWidth * 0.5) - character.x * 2;
}
else
if (leftKey)
{
//move backgrounf Roight
}
for (var b:int = 0; b < childrenOnStage; b++)
{
if (getChildAt(b).name == "enemy")
{
getChildAt(b).x +=(stage.stageWidth * 0.5) - character.x
}
}
ground.x += (stage.stageWidth * 0.5) - character.x
}
else
{
//move the background
}
// do this last, everything moves around object
character.x = stage.stageWidth * 0.5;
lastPosX = character.x;
}
Someone told me to move the objects around the player and then update the players x position.
This is what I've done by looking at a tutorial ("Cartoon Smart");
In my player class I have a reset function.
private var xSpeed:int;
private var resetPos:Point;
public function player()
{
addEventListener(Event.ADDED_TO_STAGE, onAdd)
}
private function onAdd(e: Event): void
{
xSpeed = 3;
resetPos = new Point(x, y);
}
public function reset():void
{
x = resetPos.x;
y = resetPos.y;
//trace(resetPos);
//trace(resetPos + "player");
}
When the player falls to death this function is called
private function playerFalls():void
{
if (character.y > stage.stageHeight)
{
//take life away and go back to check point or back to reset
character.x = stage.stageWidth * 0.5;
character.y = 20;
//goblin1.reset();
//goblin2.reset();
//goblin3.reset();
//stage.x = stage.stageWidth * 0.5;
//canScrollStage = false;
}
}
if I use
character.x = stage.stageWidth * 0.5;
Then my character ends up in the middle, but it will end up in the middle since the scroll function dictates the player to be in the center always.
character.x = (stage.stageWidth * 0.5) - 400;// moves him back
but if character falls off left of the screen then he is moved back.
Any one have a solution for this please?
My question is, I want to reset the player's x position to 300 and y position to 10;
But I can't do this because the stage shifts and the co ordinate system changes.
In order for the player to go back to the original coordinate of the stage, the stage must scroll.
That's my idea, or perhaps the ground and enemies must do the opposite?
I sincerely apologize for the late answer. Okay, so your saying that when the character falls you don't want the screen to scroll all the way back to the character's start position. What you need to do is find the start positions of your character and ground (as well as any other layers such as backgrounds etc). Then wherever your fall function comes into place simply set the character and background positions to their starting coordinates.
function fall(){
char.x=charStartX;
char.y=charStartY;
ground.x=groundStartX;
ground.y=groundStartY;
//etc
}
For example, let's say you have a check point. If player hits check point charResetPoint = 100. If player falls then set it's x pos to charResetPoint
But I can't move the players x position because it will always be stage.stageWidth/2 due to my code.
So in theory it will be difficult to make a resetPoint, because when I add goblin 1.x , it's x pos is 900, if I scroll right goblon1 x pos will change. Everythings x pos changes and so does the stages.
I can't get a grasp on the concept, sortlry

Issue with rectangle collision testing

I am having trouble with testing if a rectangle has collided with another rectangle and where the collision is in relation to each object (Left, right, Top, Bottom).
My code works well in theory but there are logical issues, there are false positives when an object enters the left side of another object. The parameters I have set mean that both the top collision and left collision become true when in truth only the left should be true.
image of problem
How can I stop a double positive happening in my code, I only need basic rectangle collision and nothing more. Thank you.
//Col on top?
if (Obj1.getRect(this).bottom - vSpeed < Obj2.getRect(this).bottom &&
Obj1.getRect(this).bottom - vSpeed > Obj2.getRect(this).top)
{
if (Obj1.getRect(this).right + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).left + hSpeed < Obj2.getRect(this).right)
{
Obj1.y = Obj2.y - Obj1.height;
vSpeed = 0;
colTop = true;
}
}
//Col on Bottom?
else if (Obj1.getRect(this).top - vSpeed > Obj2.getRect(this).top &&
Obj1.getRect(this).top - vSpeed < Obj2.getRect(this).bottom)
{
if (Obj1.getRect(this).right + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).left + hSpeed < Obj2.getRect(this).right)
{
Obj1.y = Obj2.y + Obj2.height;
vSpeed = 0;
colBot = true;
}
}
//Col on left side?
if (Obj1.getRect(this).right + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).right + hSpeed < Obj2.getRect(this).right)
{
if (Obj1.getRect(this).bottom - vSpeed > Obj2.getRect(this).top &&
Obj1.getRect(this).top - vSpeed < Obj2.getRect(this).bottom)
{
Obj1.x = Obj2.x - (Obj2.width * 0.5);
hSpeed = 0;
colLeft = true;
}
}
//Col on right side?
else if (Obj1.getRect(this).left + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).left + hSpeed < Obj2.getRect(this).right)
{
if (Obj1.getRect(this).bottom - vSpeed > Obj2.getRect(this).top &&
Obj1.getRect(this).top - vSpeed < Obj2.getRect(this).bottom)
{
Obj1.x = (Obj2.x + Obj2.width) + (Obj1.width * 0.5);
hSpeed = 0;
colRight = true;
}
}
You need to separate top collision from left collision by parsing the objects' relative speed. You cannot parse top/left collision using coordinates only because they are really both true if one rectangle's top left point goes inside another rectangle. So, move your Obj1 and velocity altering code out of your array of if statements, and leave the rest of the code as is. Then you check for velocities like this:
if (colTop)
if (Obj1.getRect(this).bottom > Obj2.getRect(this).top)
colTop=false;
Etc., for other collision vars. This code means: "If the bottom of Obj1 already was under the top of Obj2, then in this frame we are not hitting the top side". So, only the left side collision flag should remain. And only then you check for resultant collision vars and adjust coordinates and velocities
The starling library provides great collision detection, including simple rectangle collision. Are your methods being called on every frame?
All you would need for Starling collision detection
is:
var bounds1:Rectangle = image1.bounds;
var bounds2:Rectangle = image2.bounds;
if (bounds1.intersects(bounds2))
trace("Collision!");
collision detection

Draw random way in ActionScript

I'd like to move an AS 3 movieclip randomly. This is what I currently have, bound to the ENTER_FRAME event. This obviously moves the movieclip from the left upper to the right lower edge, so I need some kind of switch to add/substract the target positions.
function movePsycho(e:Event):void {
e.target.y += Math.random()*2;
e.target.x += Math.random()*2;
if (e.target.y >= stage.height || e.target.x >= stage.width)
e.target.removeEventListener(Event.ENTER_FRAME, movePsycho);
}
You don't need add/substract thing. You just have to make sure not only you get positive values out of your random, but negatives too, so it runs to all sides.
Try changing your random generating lines to this:
e.target.y += Math.random()*10 - 5;
e.target.x += Math.random()*10 - 5;
This will work if you want to make it move in a 5px radius.
I just realized you may want to generate a new random point on the screen, then move to that point and when your object reaches the destination generate another random point to go to. So if that's the case, try this:
mc.addEventListener(Event.ENTER_FRAME, onFrame);
var dirX:int = mc.x;
var dirY:int = mc.y;
function generateRandomPoint():void
{
dirX = Math.random() * stage.stageWidth;
dirY = Math.random() * stage.stageHeight;
}
function onFrame(e:Event):void
{
mc.x += (dirX - mc.x) * 0.1;
mc.y += (dirY - mc.y) * 0.1;
if(Math.abs(dirX - mc.x) < 1 || Math.abs(dirY - mc.y) < 1)
generateRandomPoint();
}
i don't know actionscript but you may find help with this
http://www.actionscript.org/forums/showthread.php3?t=270725

overlapping objects - help

can someone help me with the following problem please:
In my game there appear scores when you shoot down enemies. That kinda works so far but they overlap when the enemies were too close to each other when shot down.
Now what I'd like to do is to prevent the overlapping of the scores. The basic idea I had was to loop through the array of scores and to check the distance to each other.
Problem is that it doesn't work. Can someone help please?
private function checkScoreDistance():void
{
scoreManager.scoreCount = scoreManager.scores.length;
if (scoreManager.scoreCount >= 1)
{
scoreManager.scoreCount = scoreManager.scores.length - 1;
scoreManager.scoreCountTwo = scoreManager.scores.length - 2;
scoreOne: for (var scoreCtr:int = scoreManager.scoreCount; scoreCtr >= 0; scoreCtr--)
{
tempScore = scoreManager.scores[scoreCtr];
tempScore.point.x = tempScore.x;
tempScore.point.y = tempScore.y;
oldtempScoreX = tempScore.x;
oldtempScoreY = tempScore.y;
var tempScoreTwo:Score;
scoreTwo: for (var scoreCtrTwo:int = scoreManager.scoreCountTwo; scoreCtrTwo >= 0; scoreCtrTwo--)
{
tempScoreTwo = scoreManager.scores[scoreCtrTwo];
tempScoreTwo.point.x = tempScoreTwo.x;
tempScoreTwo.point.y = tempScoreTwo.y;
oldtempScoreTwoX = tempScoreTwo.x;
oldtempScoreTwoY = tempScoreTwo.y;
var scoresX:Number;
scoresX = oldtempScoreTwoX - oldtempScoreX;
var scoresY:Number;
scoresY = oldtempScoreTwoY - oldtempScoreY;
var dist:Number;
dist = Math.sqrt(scoresX * scoresX + scoresY * scoresY);
if (dist <= 25)
{
oldtempScoreX -= 25;
oldtempScoreTwoX += 25;
oldtempScoreY -= 25;
oldtempScoreTwoY += 25;
}
}
}
}
}
}
Um, you seem to be lacking some code to do something with the values you compute in oldtempScoreX and oldtemScoreTwoX. Apparently there is nothing to actually move anything based on the calculations ...
Also, what if an object is bumped left because it has a close neighbor to the right and then afterwards is bumped right because it now has a close neighbor to the left?
Also also: You seem to be blindly bumping oldtempScore to the northwest and oldtempScoreTwo to the southeast, without actually checking that their relative position is such that this makes sense.