Hey everyone so I have an object character that initially rotates around the first Movie Clip called planet which isn't apart of the array. So the user can tap the screen and the character shoots in direction it is rotating. The objective is to have the character hit the other planets in a array and when it does have it start rotating around it just like the original. Everything works fine except when I shoot the character and it lands on one of the outerplanets in aPlanetArray it doesn't start rotating around that new planet but rather just disappears.
Here is how I set it up:
character Orbits first planet that is not in the array just have it as intial orbit then remove it once leaves to other outerPlanets:
private function startOrbit():void
{
//add Planet
planet.x = (stage.stageWidth / 2);
planet.y = (stage.stageHeight / 2) + 100;
stage.addChild(planet);
//radnom number set up in main class
if (randomOrbit == 1) //If equals to one then clock wise
{
clockWiseOrbiter();
}else
if (randomOrbit == 2) //If equals to one then counter clock wise
{
counterClockWiseOrbiter();
}
}
I add outer Planets in array:
private function addOuterPlanets():void
{
for (var i:int = 0; i < nPlanets; i++)
{
outerPlanets = new mcOuterPlanets();
outerPlanets.x = startPoint.x + (xSpacing * i);
outerPlanets.y = startPoint.y - (ySpacing * i);
stage.addChild(outerPlanets);
aPlanetArray.push(outerPlanets);
}
}
In my Enter Frame Handler:
private function logicHandler(e:Event):void
{
if (!tap && !nextlevel)
{
startOrbit(); //start player orbit around planet
}
if (nextlevel)
{
startNewOrbit();
trace("Starting new Orbit");
}
//When tapped have outher planets move down
if (tap)
{
characterTap(); //Character shoots from position
}
collisionPlanetHandler();
}
When the collision happens with Outer Planets:
**** EDIT*****
private function collisionPlanetHandler():void
{
for (var i:int = 0; i < aPlanetArray.length; i++)
{
var currentPlanet:mcOuterPlanets = aPlanetArray[i];
if (character.hitTestObject(currentPlanet[i]) && !nextlevel)
{
trace("HIT");
//Have charcter orbit that planet
//startNewOrbit();
//tap back to false
tap = false;
nextlevel = true;
character.destroy();
planet.destroy();
planetHit = currentPlanet[i];
}
}
}
When the character collides with the outerPlanets in array I have the New orbit happen around the OuterPlanet it lands on. Or I at least try:
private function startNewOrbit():void
{
newClockWise();
}
private function newClockWise():void
{
for (var i:int = 0; i < aPlanetArray.length; i++)
{
var currentPlanet:mcOuterPlanets = aPlanetArray[i];
stage.addChild(character);
character.rotation = (Math.atan2(character.y - currentPlanet.y, character.x - currentPlanet.x) * 180 / Math.PI);
var rad:Number = angle * (Math.PI / 180); // Converting Degrees To Radians
character.x = currentPlanet.x + radius * Math.cos(rad); // Position The Orbiter Along x-axis
character.y = currentPlanet.y + radius * Math.sin(rad); // Position The Orbiter Along y-axis
angle += speed; // Object will orbit clockwise
}
}
I know I am doing something wrong in the startNewOrbit and newClockWise functions. I have a for loop and I am trying to target the object in array it touches. I use this var currentPlanet:mcOuterPlanets = aPlanetArray[i]; But not sure if I need to use currentObject or something equivalent. Does anyone have any idea what i am doing wrong why its not orbiting the new planet it touches but rather just disappears completely?
var planetHit:MovieClip;
function collisionTest():void{
for (loop through planets){
if (planet[i].hitTestObject(character)){
planetHit = planet[i];
}
}
}
See now the planet at that location in the array is (==) planetHit so then you can do
character.x = planetHit.x;
or
planetHit.addChild(character);
etc.
Related
I need to loop 9 squares in a diagonal row with small spaces in between. I'm not sure how to do this.
I've done it with circles before, but the code I used for circles is not working with squares
let boxA;
let curBox;
function setup()
{
createCanvas(800, 800);
stroke(255);
strokeWeight(3);
noFill();
boxA = [];
curBox = createVector(0,0);
}
function draw()
{
background(0);
for(let i = 0; i < 9; i++)
{
boxA.push(new Box(curBox.x,curBox.y));
curBox = p5.Vector.fromAngle(QUARTER_PI, (i+1) * 90);
boxA[i].show();
}
}
class Box
{
constructor(x,y)
{
this.x = x;
this.y = y;
}
show()
{
rect(this.x,this.y, 50,50);
}
}
I think this is what you're asking for. Idk, tbh. you were very vague with your question.
This code will start at 0,0 (the top left) and using p5.Vector.fromAngle, it makes a new vector from 0,0 to a new point given an angle and distance.
it then makes a new box at that new point. Simply repeat the cycle for all nine.
I am developing the below code. To give you a brief description, it is allowing the user to click on different points on the screen, then these mouse coordinates and positions are stored in an array and also seen on the screen. When the user clicks enter there is a movement from the first point to the last point, using the linear interpolation technique. I am having difficulty in the for loop as the PVector v is storing the coordinates. Could anyone please guide me accordingly?.
ArrayList vectors;
PVector v = new PVector();
boolean animate = false; //declare a boolean variable you can use to switch from building points to animating the movement
int FirstMouseClick; //declare an int variable to store the frameCount of the first mouseclick
int AnimationStart; //declare an int variable to store the frameCount of the animation start
void setup()
{
size(500, 500);
frameRate(60);
vectors = new ArrayList();
}
void draw()
{
if(!animate)//if the boolean variable animate is true
{
float output = frameCount - AnimationStart; // subract the animation start frameCount from the current frameCount so you know which framecount from the vectors array you should be showing
for(int i=0; i<vectors.size(); i++) //loop through the vectors array
//until you find the (next PVector's frameCount - frameCount of first mouseClick) > above subtraction result
{
v = (PVector)vectors.get(frameCount); //until you find the (next PVector's frameCount)
}
ellipse(v.x,v.y,10,10);// use the current pvector's xpos and ypos to draw the ellipse
}
}
void mouseClicked()
{
frameCount = 0; //if not yet set, set the first frameCount value
vectors.add(new PVector(mouseX, mouseY,frameCount));// <--- store the framecount in the z axis
ellipse(mouseX,mouseY,10,10);
println("Mouse Coordinates are: " + vectors);
}
void keyPressed()
{
if(keyCode == ENTER)
{
animate = true; //set the boolean variable animate to true
AnimationStart = 3; //set the framecount of the animation start
}
}
I'm really not sure, what you were trying to do, but if I got you right you want to do something like this:
Draw some circles, if user clicked on canvas
If user pressed Enter, start animation
Animation means: another circle (v) moves linear from circle to circle
I really don't know, what your frameCount was for. May be you can add it to this code easier now? Note, that you can add new targets by clicking with the mouse, even if animation is true.
You can do this:
ArrayList<PVector> vectors = new ArrayList();
PVector v = new PVector();
boolean animate = false; // true means, the circles moves
int nextTarget = 0; // defines the index of the next circle, the point is going to
void setup()
{
size(500, 500);
frameRate(60);
v = new PVector(width/2, height/2);
}
void draw() {
// draw background to delete old drawings
background(128);
// show all circles
for (int i=0; i<vectors.size(); i++) {
fill(255);
ellipse(vectors.get(i).x, vectors.get(i).y, 10, 10);
}
// if the boolean variable animate is true
if (animate) {
// compute angle to target circle and remaining distance
float diffX = vectors.get(nextTarget).x - v.x;
float diffY = vectors.get(nextTarget).y - v.y;
float angle = atan2(diffX, diffY);
// defines the speed of the circle
float movement = 2;
// compute new position of v
v = new PVector(v.x + sin(angle)*movement, v.y + cos(angle)*movement);
// if v reached the target circle, move on to the next one
if (dist(v.x, v.y, vectors.get(nextTarget).x, vectors.get(nextTarget).y) < 1 && nextTarget < vectors.size()-1) {
nextTarget++;
}
}
fill(0);
ellipse(v.x, v.y, 10, 10); // use the current pvector's xpos and ypos to draw the ellipse
}
void mouseClicked()
{
vectors.add(new PVector(mouseX, mouseY));
ellipse(mouseX, mouseY, 10, 10);
println("Mouse Coordinates are: " + vectors);
}
// toggle animation mode
void keyReleased() {
if (key == ENTER) {
animate = !animate;
println("animation: "+ animate);
}
}
Hey everyone so I have an array of Movie Clip Objects called aPlanetArray and what I am trying to accomplish is having all the objects in the array move down to a certain positing and then stop using tweenLite or any other method that would accomplish this. I know I can do it with y+=2 but I want all objects to move down the screen real quick in a bounce like effect using Tweenlite and to keep their distance ratios.
Here is how I have them setup when added to the stage:
//Numbers
xSpacing = 100;
ySpacing = 180;
startPoint = new Point((stage.stageWidth / 2), (stage.stageHeight / 2) );
private function addOuterPlanets():void
{
for (var i:int = 0; i < nPlanets; i++)
{
outerPlanets = new mcOuterPlanets();
outerPlanets.x = startPoint.x + (xSpacing * i);
outerPlanets.y = startPoint.y - (ySpacing * i);
stage.addChild(outerPlanets);
aPlanetArray.push(outerPlanets);
}
}
and when I tween them I am using this tweenlite function:
for each(var allPlanets:mcOuterPlanets in aPlanetArray)
{
TweenLite.to(allPlanets, 5.0, {y:550, ease:Back.easeOut});
}
This works perfect but all objects in array line up together and don't keep their spacing against one another. Any ideas would be appreciated thank you!
The simplest way would be to just have all the planets in a parent container and then move the container instead of the planets.
var planetContainer:Sprite = new Sprite();
function addPlanetsToContainer():void{
for (var i:int = 0; i < aPlanetArray.length; i++){
planetContainer.addChild(aPlanetArray[i]);
}
}
And now you can do your tween on planetContainer
Now to put the character on a planet, you can either do
planet.addChild(character);
or
character.x = planet.x + planet.parent.x;
character.y = planet.y + planet.parent.y;
I'm currently creating a small flash game using ActionScript and after receiving help for another issue I had on here, I've encountered another one when moving onto a different part of it.
This is the code I currently have:
var asteroidSpeed = 5;
var soundExplosion:Sound = new ExplosionSound();
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKDown);
var newLaser:Array = new Array();
function onKDown(e:KeyboardEvent):void {
keys[e.keyCode] = true;
if (e.keyCode == 32) {
/*laser.x = player.x + player.width/2 - laser.width/2;
laser.y = player.y;
addChild(laser);*/
for (var count=0; count < 4; count++) {
newLaser[count] = new shipLaser();
newLaser[count].x = player.x + player.width/2 - newLaser.width/2;
newLaser[count].y = player.y;
addChild(newLaser[count]);
}
}
}
var spawnTimer:Timer = new Timer(3000); //timer will tick every 3 seconds
spawnTimer.addEventListener(TimerEvent.TIMER, spawn, false, 0, true); //let's run the spawn function every timer tick
spawnTimer.start();
var spawnPoints:Array = [0,100,200,300,400,500,550]; //your list of spawn x locations
var spawnAmount:int = 4; //how many asteroids to have on the screen at once (you could increase this over time to make it more difficult)
var asteroids:Vector.<asteroidOne> = new Vector.<asteroidOne>(); //the array for your asteroids - changed to vector for possible performance and code hint improvement (basically the same as Array but every object has to be of the specified type)
spawn(); // calling it immediately
//calling this will spawn as many new asteroids as are needed to reach the given amount
function spawn(e:Event = null):void {
if(asteroids.length >= spawnAmount) return; //let's not bother running any of the code below if no new asteroids are needed
spawnPoints.sort(randomizeArray); //lets randomize the spwanPoints
var spawnIndex:int = 0;
var a:asteroidOne; //var to hold the asteroid every loop
while (asteroids.length < spawnAmount) {
a = new asteroidOne();
a.x = spawnPoints[spawnIndex];
spawnIndex++; //incriment the spawn index
if (spawnIndex >= spawnPoints.length) spawnIndex = 0; //if the index is out of range of the amount of items in the array, go back to the start
a.y = -50;
asteroids.push(a); //add it to the array/vector
addChild(a); //add it to the display
}
}
player.addEventListener(Event.ENTER_FRAME, obstacleMove);
function obstacleMove(evt:Event):void {
for (var i:int = 0; i < asteroids.length;i++) {
asteroids[i].y += asteroidSpeed;
if (asteroids[i].y > stage.stageHeight || asteroids[i].x > stage.stageWidth || asteroids[i].x < -asteroids[i].width || asteroids[i].y < -asteroids[i].height) {
//object is out of the bounds of the stage, let's remove it
removeChild(asteroids[i]); //remove it from the display
asteroids.splice(i, 1); //remove it from the array/vector
continue; //move on to the next iteration in the for loop
}
if (player.hitTestObject(asteroids[i])) {
trace("HIT");
removeChild(asteroids[i]);
asteroids.splice(i,1);
removeChild(player);
// will add end-game trigger here soon.
}
}
}
function randomizeArray(a:*, b:*):int {
return (Math.random() < .5 ) ? 1 : -1;
}
player.addEventListener(Event.ENTER_FRAME, laserCollision);
function laserCollision(evt:Event):void {
for (var i in newLaser) {
for (var a in asteroids) {
if (asteroids[a].hitTestObject(newLaser[i])) {
trace("BOOM!");
var soundExplosion:Sound = new ExplosionSound();
var channel1:SoundChannel = soundExplosion.play();
removeChild(newLaser[i]);
removeChild(asteroids[a]);
}
}
}
}
addEventListener(Event.ENTER_FRAME, laserEnter);
function laserEnter(event:Event):void {
for (var i in newLaser) {
newLaser[i].y -= laserSpeed;
// Moves the laser up the screen
if(newLaser[i].y == 0) {
removeChild(newLaser[i]);
}
}
}
What I want to do is when an instance from the newLaser array collides with an instance of the asteroids array, to remove both from the scene / indexes (but only the two that collided and not all of the ones on the scene).
Currently, when a laser hits an asteroid, it removes the asteroid but not the laser and one of the asteroids on the current row stops moving and then the next row of asteroids spawns but does not move down.
I get this error too:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at _8_fla::MainTimeline/obstacleMove()
Any help would be greatly appreciated.
You error, is likely because you are running 3 separate enter frame handlers in the same scope, and removing items from arrays and display lists (that are referenced in multiple enter frame handlers). So you asteroid is removed from the display list in one, and then you try to remove it again in another.
There are also a whole lot of other issues with your code that will cause errors and undesired results. Things like for(var i in newLasers) - in that kind of loop, i will refer to the actual laser object not the index of the array. I've re-factored your code and added lots of code comments to hopefully give you an idea of where you were going wrong:
var spawnTimer:Timer = new Timer(3000); //timer will tick every 3 seconds
var spawnPoints:Array = [0, 100, 200, 300, 400, 500, 550]; //your list of spawn x locations
var spawnAmount:int = 4; //how many asteroids to have on the screen at once (you could increase this over time to make it more difficult)
var asteroidSpeed = 5;
var asteroids:Vector.<asteroidOne> = new Vector.<asteroidOne>(); //the array for your asteroids - changed to vector for possible performance and code hint improvement (basically the same as Array but every object has to be of the specified type)
var lasers:Vector.<shipLaser> = new shipLaser(); //the array of lasers
var maxLasers:int = 4; //the maximum amount lasers allowed at any given time
var soundExplosion:Sound = new ExplosionSound();
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKDown);
player.addEventListener(Event.ENTER_FRAME, gameLoop);
spawnTimer.addEventListener(TimerEvent.TIMER, spawn, false, 0, true); //let's run the spawn function every timer tick
spawnTimer.start(); //start the spawn timer
spawn(); // calling it immediately
function onKDown(e:KeyboardEvent):void{
if (e.keyCode == 32) {
//create ONE laser per button push (instead of 4 identical lasers)
if(lasers.length < maxLasers){ //if player hasn't reached the maximum amount of lasers available
var tmpLaser:shipLaser = new shipLaser();
tmpLaser.x = player.x + player.width / 2 - tmpLaser.width / 2;
tmpLaser.y = player.y;
addChild(tmpLaser);
lasers.push(tmpLaser);
}
}
}
//calling this will spawn as many new asteroids as are needed to reach the given amount
function spawn(e:Event = null):void {
if (asteroids.length >= spawnAmount)
return; //let's not bother running any of the code below if no new asteroids are needed
spawnPoints.sort(randomizeArray); //lets randomize the spwanPoints
var spawnIndex:int = 0;
var a:asteroidOne; //var to hold the asteroid every loop
while (asteroids.length < spawnAmount)
{
a = new asteroidOne();
a.x = spawnPoints[spawnIndex];
spawnIndex++; //incriment the spawn index
if (spawnIndex >= spawnPoints.length)
spawnIndex = 0; //if the index is out of range of the amount of items in the array, go back to the start
a.y = -50;
asteroids.push(a); //add it to the array/vector
addChild(a); //add it to the display
}
}
function gameLoop(e:Event):void {
//LOOP through all the asteroids, give it a label (asteroidLoop) so we can break/continue it inside other loops
asteroidLoop: for (var i:int = 0; i < asteroids.length; i++) {
//check if asteroid is out of bounds
if (asteroids[i].y > stage.stageHeight || asteroids[i].x > stage.stageWidth || asteroids[i].x < -asteroids[i].width || asteroids[i].y < -asteroids[i].height) {
//object is out of the bounds of the stage, let's remove it
removeChild(asteroids[i]); //remove it from the display
asteroids.splice(i, 1); //remove it from the array/vector
continue; //forget the rest of the code below and move on to the next iteration in the for loop since the asteroid is gone
}
//check if any lasers are colliding with this asteroid
for (var j:int = lasers.length-1; j >= 0;j--) { //iterate over all lasers backwards
if (asteroids[i].hitTestObject(lasers[j])){
trace("BOOM!");
var soundExplosion:Sound = new ExplosionSound();
var channel1:SoundChannel = soundExplosion.play();
//remove the asteroid
removeChild(asteroids[i]); //remove it from the display
asteroids.splice(i, 1); //remove it from the array/vector
//remove the laser
removeChild(lasers[j]);
lasers.splice(j, 1);
continue asteroidLoop; //break completely out of this inner for-loop (lasers) since the asteroid in the outer loop was removed, and move on to the next asteroid
}
}
//check if this asteroid collides with the player
if (player.hitTestObject(asteroids[i])){
trace("HIT");
//remove the asteroid
removeChild(asteroids[i]); //remove it from the display
asteroids.splice(i, 1); //remove it from the array/vector
removeChild(player);
spawnTimer.stop(); //stop spawning new asteroids
//will add end-game trigger here soon.
break; //break completely out of the asteroid loop if it's game over (as there's no point in checking the rest of the asteroids)
}
//we've made it this far, so let's just move this asteroid
asteroids[i].y += asteroidSpeed;
}
for (var i:int = lasers.length-1; i >= 0;i--) { //iterate backwards
lasers[i].y -= laserSpeed;
// Moves the laser up the screen
if (lasers[i].y <= 0){ //make this less than or equal to 0
removeChild(lasers[i]); //remove the laser from the display list
lasers.splice(i, 1); //remove the laser from the array
}
}
}
function randomizeArray(a:*, b:*):int {
return (Math.random() < .5) ? 1 : -1;
}
I have an array of skin tone hex codes. At the moment, when I click a button, it randomly gets an element from the array. I'd like it to just get the next available element and if there are no more, loop back to the 1st element. Here's what I have at the moment.
var skinTones:Array = ["0xebae7f","0x754c24","0xf2ca8d","0xf4d1b7","0x8b6947"];
And the button code:
menuMC.buttFace.addEventListener(MouseEvent.CLICK, clickFace);
function clickFace(event:MouseEvent): void
{
function getSkinTone(source, amount) {
var i = Math.round(Math.random() * (source.length - 1)); //random seed (starting point)
var myTone = new Array(); //the new array
while(myTone.length < amount){
if (i >= source.length) i = 0; //if the current iterator if out of bounds, reset to 0
myTone.push(source[i]);
i++;
}
return myTone;
}
var toneHex = getSkinTone(skinTones,1);
trace(toneHex);
TweenLite.to(faceWrapperMC.faceMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.earsMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.eyesMC.eyes.eyelid, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
}
Any help would be great. Also, if it can be simplified, please let me know. This is my 1st AS3 project.
This will take the passed array, and return a new array with a random seed (starting element) and keep the rest of the order the same. I renamed the parameters to better clarify what I interpreted them to be.
function getSkinTone(source:Array,amount:int):Array {
var i:int = Math.round(Math.random() * (source.length - 1)); //random seed (starting point)
var myTone:Array = new Array(); //the new array
while(myTone.length < amount){
if (i >= source.length) i = 0; //if the current iterator if out of bounds, reset to 0
myTone.push(source[i]);
i++;
}
return myTone;
}
EDIT
After some comments, I believe this is what you'd like to do:
var skinTones:Array = ["0xebae7f","0x754c24","0xf2ca8d","0xf4d1b7","0x8b6947"]; //these can be stored as uint instead of strings since TweenLite will just convert them to uint anyway
var skinToneIndex:int = -1; //a global var to hold the current index - starting as -1 to indicate it hasn't been set yet.
function getNextSkinTone():String {
if(skinToneIndex == -1) skinToneIndex = Math.round(Math.random() * (skinTones.length - 1)); //if not set, make it a random starting number
skinToneIndex++; //increment it
if(skinToneIndex >= skinTones.length) skinToneIndex = 0; //if out of bounds reset to 0;
return skinTones[skinToneIndex];
}
menuMC.buttFace.addEventListener(MouseEvent.CLICK, clickFace);
function clickFace(event:MouseEvent): void {
var toneHex:uint = getNextSkinTone();
trace(toneHex);
TweenLite.to(faceWrapperMC.faceMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.earsMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.eyesMC.eyes.eyelid, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
}