I'm new on here and needing a little help. Basically I'm designing a Pac-man like game which it has to be based on Wind in the Willows, so Mole-man it is!!
Anyway, I've done the basics of it, I've made my 2d mole, made him move, made him react to button presses etc. and now trying to get the walls to work, starting with the outer walls.
I made 4 rectangles around the edge, merged them to one shape and called it "outerWalls". I've been using hitTestObject to try and get it to work but with no success.
I did a test to make it work with moleman.xIncrement = -5 which makes him immediately move backwards without touching any walls. I am curious as to if this is because he is inside of the walls and it classes 4 outer walls as a square overall and as he is already inside the theoretical square moves him out? I am unsure. Have some code!!
Actions layer - frame 1:
import flash.events.KeyboardEvent;
var moleman = this.addChild(new Moleman_mc());
moleman.x = 100;
moleman.y = 200;
moleman.width = 24;
moleman.height = 24;
moleman.xIncrement = 5;
moleman.yIncrement = 0;
stage.addEventListener(KeyboardEvent.KEY_DOWN, doKeyDown);
function doKeyDown (e:KeyboardEvent):void
{
switch(e.keyCode)
{
case Keyboard.UP:
moleman.xIncrement = 0;
moleman.yIncrement = -5;
moleman.rotation = -90;
break;
case Keyboard.DOWN:
moleman.xIncrement = 0;
moleman.yIncrement = 5;
moleman.rotation = 90;
break;
case Keyboard.LEFT:
moleman.xIncrement = -5;
moleman.yIncrement = 0;
moleman.rotation = 180;
break;
case Keyboard.RIGHT:
moleman.xIncrement = 5;
moleman.yIncrement = 0;
moleman.rotation = 0;
break;
}
}
Actions layer - frame 2:
import flash.events.Event;
var collectCounter:int = 0;
moleman.x += moleman.xIncrement;
moleman.y += moleman.yIncrement;
if(moleman.hitTestObject(collect))
{
collectCounter ++;
collect.visible = false;
}
moleman.addEventListener(Event.ENTER_FRAME, wallHit);
function wallHit(event:Event):void
{
if(moleman.hitTestObject(outerWalls))
{
moleman.stop();
}
}
Actions layer - frame 3:
gotoAndPlay(2);
In addition, I cannot get the collect (e.g. collectables) to work, the plan would be to make it so each time you collect one "collect" item, that one disappears, you add one to collectCounter but all others stay visible. Currently if you collect one "collect" item, moleman just stops and stays where he is while another moleman appears and continues, not very useful. Any help on this would also be appreciated, not sure where to take it from there.
Any help is much appreciated, I am new at this but hoping it can go well :)
All help is much appreciated.
John.
In your case to detect collision you should use hitTestPoint method instead of hitTestObject. hitTestPoint method has the signature:
public function hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean
so, when shapeFlag is set to true, it is possible to detect collision with the point (your hero) and maze shape (or any other arbitrary shape). This method is very powerful because the intersection with the real shape, not its bounding box is calculated. Modified wallHit method may look like this:
moleman.addEventListener(Event.ENTER_FRAME, wallHit);
function wallHit(event:Event):void
{
if(outerWalls.hitTestPoint(moleman.x, moleman.y, true))
{
// collision
moleman.x += -moleman.xIncrement;
moleman.y += -moleman.yIncrement;
moleman.xIncrement=0;
moleman.yIncrement=0;
}
moleman.x += moleman.xIncrement;
moleman.y += moleman.yIncrement;
if(moleman.hitTestObject(collect))
{
collectCounter ++;
collect.visible = false;
}
}
you may also remove frame 3 and "gotoAndPlay(2);" call because it is better to put the code which controls hero's position into ENTER_FRAME handler either.
Related
Hey everyone so I've been at this for awhile now and finally decided to ask for some help. So I am creating a game in AS3 where the object rotates in a circular motion from either left to right depending on the users mouse Presses. So I have some variables set up to act as friction. What I AM trying to accomplish is when the object is greater or less than a certain rotation degree I want the object to feel like it being pulled more and more to that side that it is currently at and the only way the object can say come back to its original position is if the use clicks on the mouse enough so their is no more force acting on it and say the speed increases at the same time for difficulty.
Here are the Variables I am currently working with:
//Variables
speed = 0.2;
vx = 0;
friction = 0.93;
maxspeed = 10;
I also have these buttons on stage so the user can click them to change the rotation of the objectlike so:
mainScreen.leftBtn.addEventListener(MouseEvent.CLICK, leftButtonClicked);
mainScreen.rightBtn.addEventListener(MouseEvent.CLICK, rightButtonClicked);
private function leftButtonClicked(e:MouseEvent):void
{
clickLeft = true;
clickRight = false;
}
private function rightButtonClicked(e:MouseEvent):void
{
clickRight = true;
clickLeft = false;
}
and I try to set up the mechanics in my ENTER_FRAME event listener like so:
//RIGHT = CLOCKWISE +, Left = COUNTER CLOCKWISE -
if (clickRight)
{
vx += speed;
moveSlow = true;
moveFast = false;
}else
if (clickLeft)
{
vx -= speed;
moveSlow = true;
moveFast = false;
}else
{
vx *= friction;
}
//IF object is Past 15 Degrees make object go faster MOVE FAST
if (object.rotation > 15)
{
moveFast = true;
moveSlow = false;
trace("MOVE_FAST");
}else
if (object.rotation < - 15)
{
moveFast = true;
moveSlow = false;
}else
{
vx *= friction;
}
object.rotation += vx;
//lumberJack.rotation += speed;
//boundaries of object
if (vx > maxspeed)
vx = maxspeed;
else if (vx < -maxspeed)
vx = -maxspeed;
I know I need to add something in the if object.rotation statement but not to sure what i also know i need to add something in the Mouse clicked event listeners to manipulate either speed or friction so the user can pull away from the force acting on it. I tried several time but still cant seem to figure it out. As of now the object rotates left or right depending on the users input and say the object is moving left and the user presses right the object slowly moves back to the left then returns to normal speed.
Please If anyone can help me figure this out I will greatly appreciate it!
To be honest I am having a little bit of trouble following your question, so this may only be a partial answer. I know, bad me, but I don't have enough stupid internet points to leave a comment, so this is all I can do to help, and I just can't care about the internet point system anymore.
First, for the love of insert deity, clean up all that unnecessary white space.
Here's a potential problem in your code: the rotation property of display objects returns a value between -180 and 180. This means that every 180 degrees, the rotation value changes sign. So you can't use whether the rotation is positive or negative to determine which direction the object is rotating in. That should be stored in a separate variable.
Another thing to consider: if moveSlow and moveFast are never true at the same time, you don't need to have two variables because it's redundant. You don't make use of those variables in your code above, but assuming you wrote this:
if (moveSlow) {
moveALittleBit();
} else if (moveFast) {
moveALot();
}
You could replace it with:
if (moveSlow) {
moveALittleBit();
} else {
moveALot();
}
Not only is that giving yourself unnecessary work, but it's bad because it means you can create "invalid states" (i.e. if you make a mistake and "moveSlow" and "moveFast" are both true at the same time).
Likewise, you shouldn't need separate variables for "clickedLeft" and "clickedRight" if they are both mutually exclusive. If they can both be false at the same time, however, you might be better off with something like:
clickDirection = "left";
clickDirection = "right";
clickDirection = "none";
If you went that route, you'd be better off using string constants instead of hardcoded strings, but I think that's getting too off-topic.
After reading your question many times, it sounds like maybe what you are looking for is momentum. Does this cover what you need?
if (clickRight)
{
vx += speed;
momentum = 0;
} else if (clickLeft)
{
vx -= speed;
momentum = 0;
} else
{
vx *= friction;
}
//IF object is Past 15 Degrees make object go faster MOVE FAST
if (object.degreesRotated > 15)
{
momentum += 1;
}else if (object.degreesRotated < - 15)
{
momentum -= 1;
}else
{
vx *= friction;
}
vx += momentum;
object.rotation += vx;
object.degreesRotated += vx; //remember how much we've rotated
//lumberJack.rotation += speed;
If object is a dynamic type, you can add the "degreesRotated" property whenever you feel like it. Otherwise, you might have to make a new class by extending whatever display type that object is, and add the degreesRotated field to that class
We have an object (mc_robert) that collides with another object (mc_left). When the collision occurs, we have an action take place. What we're trying to figure out is how to change the collision box of the object (mc_robert) so that the objects overlap when the collision detects. We don't want the default collision box of the object (mc_robert). Any help that can be offered would be greatly appreciated.
This is what we have for our code currently:
var numX:Number = 0;
var numY:Number = -2;
addEventListener(Event.ENTER_FRAME,loop);
function loop(e:Event)
{
mc_robert.y += numY;
mc_robert.x += numX;
if (mc_robert.hitTestObject(mc_left))
{
numX = -2;
numY = 0;
mc_robert.rotation = -90;
}
}
For pixel perfect collision convert the shapes into BitmapData and use the BitmapData's Hit-test method.
If you don't want to do the above approach you can use hitTestPoint and create multiple points in a for loop to do the collision.
eg: Haven't tested the following code but the concept is there. This will create a bounding box, or you can use some trig to collide from a circle or custom create the points.
for(var y:int = 0;y<2;y++){
for(var x:int=0;x<2;x++){
var w:int = mc2.width*x;
var h:int = mc2.height*y;
if(mc1.hitTestPoint(mc2.x+w, mc2.y+h, true)){
trace("collides");
}
}
}
How ever the solution I would use for the best accuracy would be a BitmapData collision.
Hey Guys so I'm having a little trouble creating Multiple levels. I'm not so sure if im creating them the right way but i have a player and goal_1, goal_2, etc.. Basically when the player hitTestObject the goal_1 i want it to go to a new function called level_2 then level_3 after that hitTest. so Level_1 works just fine the hitTest works and it initializes level_2 but when i try to hitTest the player and goal_2 or even goal_1 again it just goes through it and doesnt do anything.
I understand now that level_2 isnt being called every frame like level_1 since its not part of the Enter_Frame listener. But i cant figure out how to have multiple Enter Frame events and not have them run simultaneously. If thats even the right way to create multiple levels.
Can you see what i could do in order to make it work?
private function gameLoop(e:Event):void
{
playerShoot();
playerControl();
playerStageBoundaries();
checkEndGameCondition();
checkPlayerOffScreen();
level_1();
}
private function level_1():void
{
if(player.hitTestObject(mGoal_1))
{
trace("Goal_1 Collision");
//Remove button for constant movement
btnShootPlayer = false;
mGoal_1.destroyGoal_1();
player.destroyPlayer();
//Update High Score text
nScore += 10;
updateHighScore();
stage.removeEventListener(Event.ENTER_FRAME, gameLoop);
//Update level
nLevel++;
updatePlayerLevel();
level_2();
}else
{
checkEndGameCondition();
}
}
public function level_2():void
{
stage.addEventListener(Event.ENTER_FRAME, gameLoop);
TweenMax.to(mGoal_1, 1, {y:40, repeat:-1, yoyo:true, ease:Power0.easeInOut});
trace("Level_2 Initiated");
//Keep Text Scores initiated
updateHighScore();
updatePlayerLives();
player = new mPlayer();
stage.addChild(player);
player.x = (stage.stageWidth / 2) - 280;
player.y = (stage.stageHeight / 2);
mGoal_1 = new goal_1();
stage.addChild(mGoal_1);
mGoal_1.x = (stage.stageWidth / 2) + 300;
mGoal_1.y = (stage.stageHeight) - 35;
if (player.hitTestObject(mGoal_1))
{
trace("Level 2 Hit test works!");
nScore += 10;
updateHighScore();
}
}
I didn't read too carefully all the code, but I guess you can use a function variable. Declare it on class level (outside any function):
var _doFunction:Function;
than, instead calling level1 function, pass the reference and call the _doFunction:
_doFunction = level1;
_doFunction();//or _doFunction.call(); - see Adobes documentation
when you are done with the level1, than pass the next level:
_doFunction = level2;
P.S. don't forget to accept the answer if it helped to solve your problem.
I have a student who is working on a Tower Defense game in AS3 and has an issue that has stumped me. He is using hitTestObject to change the direction that a movieClip is moving. The movieClip has its own timeline with frames for the different directions that the object is facing and a linked .as file with the code for the behavior of the object.
When he calls gotoAndStop to change the internal frame of the movieClip, the removed event is triggered, but the object stays on the screen and no longer moves.
All of my searches find answers about removing objects, but I have not seen anything about preventing an object from removing itself.
The following code is a loop triggered by an ENTER_FRAME event in the .as class file for the movieClip object:
private function eFrame(event:Event):void
{
if (_root.isPaused == false)
{
//MOVING THE ENEMY
this.x += speed * xDir;
this.y -= speed * yDir;
if (health <= 0)
{
_root.currency += 4;
this.parent.removeChild(this);
}
if (this.x > 770)
{
this.parent.removeChild(this);
_root.health -= 10;
_root.gotHit = true;
}
//checking if touching any invisible markers
for (var i:int=0; i<_root.upHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var upMarker:DisplayObject = _root.upHolder.getChildAt(i);
if (hitTestObject(upMarker))
{
yDir = 1;
xDir = 0;
this.gotoAndStop(3);
}
}
for (i=0; i<_root.downHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var downMarker:DisplayObject = _root.downHolder.getChildAt(i);
if (hitTestObject(downMarker))
{
yDir = -1;
xDir = 0;
this.gotoAndStop(7);
}
}
for (i=0; i<_root.rightHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var rightMarker:DisplayObject = _root.rightHolder.getChildAt(i);
if (hitTestObject(rightMarker))
{
yDir = 0;
xDir = 1;
this.gotoAndStop(6);
}
}
for (i=0; i<_root.leftHolder.numChildren; i++)
{
//the process is very similar to the main guy's testing with other elements
var leftMarker:DisplayObject = _root.leftHolder.getChildAt(i);
if (hitTestObject(leftMarker))
{
yDir = 0;
xDir = -1;
this.gotoAndStop(2);
}
}
}
}
private function remove(event:Event):void
{
trace("remove");
removeEventListener(Event.ENTER_FRAME, eFrame);
_root.enemiesLeft -= 1;
}
}
When the gotoAndStop line executes, the frame of the movieClip changes and then the code jumps directly to a function that is triggered by the REMOVED event.
Does anyone have an idea why the REMOVED event might be triggered by this code?
Thank you for your help.
The REMOVED Event is triggered by anything that is removed from the stage inside the MovieClip or Sprite that is containing it, if I'm not mistaken. And especially with MovieClips that have animation, things get removed and added everytime, for instance if some part of the animation ends on the timeline, or at keyframes.
Event.REMOVED_FROM_STAGE is dispatched only when the container itself is removed from stage. Maybe that's causing your confusion? I can't see from your code example exactly what event type you're listening for.
Where are you adding the remove-listener?
Without more information, I would guess that you are listening to a clip inside an animation, and that it's not there on all frames (or, maybe even more likely - that the instance is being swapped out for another, identical one, by flash pro. This can happen depending on in what order you added keyframes, the alignment of the moon and fluctuations in the ionosphere. It's easiest fixed by simply removing all key-frames and then re-creating them. And then never using flash pro for anything ever again.)
I'm current building a game in as3; the proplem I have right now is when I roll the virtual dice, the player(marker) moves accross the board but what I need to know is: is there a way to find the instance name of the object(box) that the player lands on?
And Sorry my english isn't good.
It depends a lot on how your board is laid out. One way is to put all of the objects your player can land on into an array, then check the player's x and y coordinates to see if they fall inside of each object's box.
For example:
var boardObjects:Array; // This would contain references to all the objects the
// player object might land on. Initialize it, then use boardObjects.add(object)
// on each one until they're all in the array.
// once the player has moved:
for(var i:int = 0; i < boardObjects.size; i++) {
var obj:* = boardObjects[i];
if (player.x >= obj.x && player.x <= obj.x + obj.width) {
if (player.y >= obj.y && player.y <= obj.y + obj.height) {
// If these if statements are all true, the Player's top-left corner
// is inside the object's bounding box. If this is a function,
// here is a good spot to put a return statement.
}
}
}
You may want to calculate it based on the middle of the player rather than their top-left corner, in which case just add half the player's width to their x position and half their height to their y position.
For performance (and avoiding unnecessary code), if it's tile based / dice why not do something like this
private function rollDice(){
var results:Array = [Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6)] //Accurately simulates two 6 sided dice
dice1.rollAnimation(results[0]);
dice2.rollAnimation(results[1]);
player.position += results[0] + results[1];
}
The board would be an array, and in Player you can use getters/setters to 'wrap' the board like this
private var _position:int = 0;
public function get position():int{
return _position;
}
public function set position(value:int){
_position = value;
while(_position > GameBoard.TILES){
_position -= GameBoard.TILES;
}
x = //Whatever you determine the positioning of the player..
}