So I'm making a collision detection when player touches an object. When it touches the object, you move and stop when colliding, but for example, if I press the D key to go right, and I press the A key and let go, then the player starts moving through the object.
This is my player moving code.
public function onKeyDown(event: KeyboardEvent): void
{
if (event.keyCode == Keyboard.D)
{
isRight = true;
}
if (event.keyCode == Keyboard.A)
{
isLeft = true;
}
if (event.keyCode == Keyboard.W)
{
isUp = true;
}
if (event.keyCode == Keyboard.S)
{
isDown = true;
}
}
private function onKeyUp(event: KeyboardEvent): void
{
if (event.keyCode == Keyboard.A || event.keyCode == Keyboard.D)
{
vx = 0;
}
else if (event.keyCode == Keyboard.S || event.keyCode == Keyboard.W)
{
vy = 0;
}
}
public function onEnterFrame(event: Event): void
{
if (isRight)
{
vx = 5;
x += vx;
}
if (isLeft)
{
vx = 5;
x -= vy;
}
if (isUp)
{
vx = 5;
y -= vy;
}
if (isDown)
{
vx = 5;
y += vy;
}
//collision detection
if (player.collisionArea.hitTestObject(wall0))
{
player.x -= vx;
player.y -= vy;
}
}
Your issue, is that vx is always 5. So one direction you subtract 5 from the x, the other direction you add it.
Yet in your collision if statement, you are always subtracting it from the player's x (which if moving left, would keep moving the player left until it's past the object it's colliding with).
Also, in your isLeft check, you are subtracting the vy value, but I imagine you want to actually subtract the vx value. On that same note, in your isUp/isDown checks, your set the vx var to 5, but it seems like you should be setting the vy.
As it's unclear what x and y affect in context to the player, it's hard to give you an exact code example.
Most likely, you just need to move the player to the wall edge, and choose the side based off the direction of the player:
//collision detection
if (player.collisionArea.hitTestObject(wall0))
{
//if the player x is colliding
if(player.x + player.width > wall0.x && player.x < wall0.x + wall0.width){
player.x = isRight ? wall0.x - player.width : wall0.x + wall0.width;
}else if(player.y + player.height > wall0.y && player.y < wall0.y + wall0.height){
player.y = isDown ? wall0.y - player.height : wall0.y + wall0.height;
}
}
Related
I'm very new to ActionScript3 and am making an asteroids-type game. Right now, the ship continues floating in a straight line when you let go of the movement buttons, and I want to be able to stop that from happening. I'm thinking either a dedicated button for braking, like the b key, or if the keys are not pressed to stop movement, whichever would be easier. Like I said I'm really new to AS3 so not even sure what part of my code is making them keep flying in a straight line. Here is the code to control movement for reference:
// register key presses
public function keyDownFunction(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = true;
} else if (event.keyCode == 39) {
rightArrow = true;
} else if (event.keyCode == 38) {
upArrow = true;
//Add event listener for down arrow
} else if (event.keyCode == 40) {
downArrow = true;
// show thruster
if (gameMode == "play") ship.gotoAndStop(2);
} else if (event.keyCode == 32) { // space
var channel:SoundChannel = shootSound.play();
newMissile();
} else if (event.keyCode == 90) { // z
startShield(false);
var channel:SoundChannel = shieldSound.play();
}
}
// register key ups
public function keyUpFunction(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = false;
} else if (event.keyCode == 39) {
rightArrow = false;
} else if (event.keyCode == 38) {
upArrow = false;
//Add listener for down arrow
} else if (event.keyCode == 40) {
downArrow = false;
// remove thruster
if (gameMode == "play") ship.gotoAndStop(1);
}
}
// animate ship
public function moveShip(timeDiff:uint) {
// rotate and thrust
if (leftArrow) {
ship.rotation -= shipRotationSpeed*timeDiff;
} else if (rightArrow) {
ship.rotation += shipRotationSpeed*timeDiff;
} else if (upArrow) {
shipMoveX += Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY += Math.sin(Math.PI*ship.rotation/180)*thrustPower;
//Added down arrow movement to allow player to move backwards
} else if (downArrow) {
shipMoveX -= Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY -= Math.sin(Math.PI*ship.rotation/180)*thrustPower;
}
// move
ship.x += shipMoveX;
ship.y += shipMoveY;
I agree that there is a little logic problem in your code. Your ship will move on 'til
judgement day because the two variables responsible for the speed of it's motion - shipMoveX
and shipMoveY - aren't automatically degraded over time.
Now there are literally thousands of ways of how this could be achieved but let's keep things
simple.
You are using a class variable called thrustPower - make sure to set it to 0.1 and that the value of both shipMoveX & shipMoveY is 0.
Additionally add these class variables:
private var thrustHorizontal:Number = 0;
private var thrustVertical:Number = 0;
private var speed:Number = 0;
private var maxSpeed:Number = 5;
private var decay:Number = 0.97;
Replace the moveShip function with this:
public function moveShip(timeDiff:uint):void
{
thrustHorizontal = Math.sin(Math.PI * ship.rotation / 180);
thrustVertical = Math.cos(Math.PI * ship.rotation / 180);
// rotate and thrust
if (leftArrow)
{
ship.rotation -= shipRotationSpeed * timeDiff;
}
else if (rightArrow)
{
ship.rotation += shipRotationSpeed * timeDiff;
}
else if (upArrow)
{
shipMoveX += thrustPower * thrustHorizontal;
shipMoveY += thrustPower * thrustVertical;
}
else if (downArrow)
{
shipMoveX -= thrustPower * thrustHorizontal;
shipMoveY -= thrustPower * thrustVertical;
}
if (!upArrow && !downArrow)
{
shipMoveX *= decay;
shipMoveY *= decay;
}
speed = Math.sqrt((shipMoveX * shipMoveX) + (shipMoveY * shipMoveY));
if (speed > maxSpeed)
{
shipMoveX *= maxSpeed / speed;
shipMoveY *= maxSpeed / speed;
}
ship.x += shipMoveX;
ship.y -= shipMoveY;
}
As you can see, there is this new if-block:
if (!upArrow && !downArrow)
{
shipMoveX *= decay;
shipMoveY *= decay;
}
Here we're handling the case, if the player neither pressed up nor down and multiply
the spaceships horizontal/vertical speed by decay. If you scroll back a bit, you notice
it's value is 0.97.
You can generally say, if you multiply a positive number x by 0 < y < 1, x will become smaller.
So if you're spaship is currently moving horizontally at 3 pixels per frame (shipMoveX=3 ; shipMoveY=0)
it will become 2.91 the next frame. The next frame it will be 2.8227, then 2.738019 ... and so on before it will finally reach zero in infinity.
I'm making a frogger game in AS3 and when you press up, down, left and right, you "skip" a certain amount of space instead of gradually moving there like in most platformers now. How would I be able to do this?
Currently he moves up left, down and right on their respective keys. But he gradually moves there, not skipping the amount of space like in the real frogger.
Any ideas on how I could do this?
Code:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
function keyDownHandler(event:KeyboardEvent):void{
if (event.keyCode == Keyboard.UP){
trace("frogger up");
player.y -= 5;
}
if(event.keyCode == Keyboard.DOWN){
trace("frogger down");
player.y += 5;
}
if(event.keyCode == Keyboard.LEFT){
trace("frogger left");
player.x -= 5;
}
if(event.keyCode == Keyboard.RIGHT){
trace("frogger right");
player.x += 5;
}
}
One way to do is to increase the X and Y with a certain amount like as Marty said in the comment, with 50.. or you could create two variables, let's name them xPosition & yPosition.
When holding down the keys, you would just increase/decrease these variables by 1, and then call a positioning function which would calculate the new position of the player depending on the xPosition and yPosition 's values and of course the grid sizes.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
var xPosition:int = 0;
var yPosition:int = 0;
var gridWidth:int = 32;
var gridHeight:int = 32;
function keyDownHandler(event:KeyboardEvent):void{
if (event.keyCode == Keyboard.UP){
yPosition--;
repositionPlayer();
}
if(event.keyCode == Keyboard.DOWN){
yPosition++;
repositionPlayer();
}
if(event.keyCode == Keyboard.LEFT){
xPosition--;
repositionPlayer();
}
if(event.keyCode == Keyboard.RIGHT){
xPosition++;
repositionPlayer();
}
}
function repositionPlayer():void{
player.x = gridWidth*xPosition;
player.y = gridHeight*yPosition;
}
This gives you a big advantage in case you want to change the grid size.
I have a problem. I have made movement with friction and ease out code runs perfectly the first time it runs but doesn't run properly after the first run. I have added trace commands to debug and after the first time it runs the vx value returns NaN.
leftPressed is a Boolean
righPressed is a boolean
vx is the x velocity
friction is the speed of the ease out
public var vy:Number = 30;
public var vyInitial:Number;//This is initialised later
public var gravity:Number = 2.0;
public var vx:Number = 0.4;
public var vxInitial:Number;//This is initialised later
public var friction:Number = 0.4;
Here is the code used: Including the jumping ease code that works fine.
if (leftPressed)
{
if (vx == 0)
{
vx = vxInitial;
}
char.x -= vx;
lastMove = "Left";
}
else if (rightPressed)
{
if (vx == 0)
{
vx = vxInitial;
}
char.x += vx;
lastMove = "Right";
}
else if (rightPressed == false && leftPressed == false)
{
if (lastMove == "Right" && rightPressed == false && leftPressed == false)
{
vx -= friction;
trace(vx);
if (vx < 0)
{
lastMove = "No Move";
trace("lastMove Right");
vx = 0;
}
else if (vx > 0)
{
trace("moving left");
char.x += vx;
}
}
else if (lastMove == "Left" && rightPressed == false && leftPressed == false)
{
vx -= friction;
trace(vx);
if (vx < 0)
{
lastMove = "No Move";
trace("lastMove Left");
vx = 0;
}
else if (vx > 0)
{
trace("moving LEft");
char.x -= vx;
}
}
}
It appears that this line:
if (vx == 0)
{
vx = vxInitial;
}
Would not get called the first time, since vx is initially equal to 0.4 (not zero). During the first run vx is set to zero though:
if (vx < 0)
{
lastMove = "No Move";
trace("lastMove Right");
vx = 0;
}
So the next time it is run vx is set to the value of vxInitial, which appears to have no value:
public var vxInitial:Number;//This is initialised later (Is it?)
Set vxInitial and it shouldn't error.
Sorry if this is obvious to others, but I can't get my head around something in ActionScript 3.0 (huge n00b btw)
I have this code for controlling velocity:
public function keyDownHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
vx = -5;
}
else if (event.keyCode == Keyboard.RIGHT)
{
vx = 5;
}
else if (event.keyCode == Keyboard.UP)
{
vy = -5
}
else if (event.keyCode == Keyboard.DOWN)
{
vy = 5;
}
}
When run, if I hold both LEFT and UP the Sprite moves Diagonally, but the fact that the two last conditionals (Keyboard.UP & Keyboard.DOWN) are elseifs should prevent them from being evaluated at all shouldnt it?
Is anyone able to shed some light on the behaviour?
When you press both buttons flash fires two independent events for each button. If you want to skip this case, you can make state flags (leftPressed, rightPressed, etc) for each button, change state in key handler and call the check motion method according to current states of each button.
If you don't want diagonal movement, set the velocity components to zero first like this:
public function keyDownHandler(event:KeyboardEvent):void
{
vx = vy = 0; ////
if (event.keyCode == Keyboard.LEFT)
{
vx = -5;
}
else if (event.keyCode == Keyboard.RIGHT)
{
vx = 5;
}
else if (event.keyCode == Keyboard.UP)
{
vy = -5
}
else if (event.keyCode == Keyboard.DOWN)
{
vy = 5;
}
}
So I am currently trying to do a game which is almost like a maze.
The problem is with the wall collision, once the character hits a wall, I can't get him out anymore, he gets "stuck" no matter what direction I try to take him after the collision.
One of the solutions I was thinking would be to whenever the character hits the wall, to "back him up", so that there is no more collision detected. However, when I do that, he goes through the wall in a strange way.
Here is my code so you guys can have an idea of what I'm doing:
function keyPressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = true;
if(char.hitTestObject(test))
{
leftHit= true;
} else {
leftHit = false;
}
}
if (event.keyCode == Keyboard.RIGHT)
{
rightArrow = true;
if(char.hitTestObject(test))
{
rightHit= true;
} else {
rightHit = false;
}
}
}
function keyReleased(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = false;
}
if (event.keyCode == Keyboard.RIGHT)
{
rightArrow = false;
}
}
function walking(event:Event):void {
if (rightArrow) {
if(rightHit)
char.x -= speed;
else
char.x += speed;
}
if (leftArrow) {
if(leftHit)
char.x += speed;
else
char.x -= speed;
}
}
A big part of this code I actually got from another person asking the same question. Even doing what was suggested in the other topic, the problem still remains.
Thank you very much for any help!
As requested, here is my solution:
if (rightArrow) {
if (!test.hitTestPoint(MovieClip(root).char.x+speed, MovieClip(root).char.y, true))
{
MovieClip(root).char.x += speed;
x = x-speed; //moving the background
}
}
if (leftArrow) {
if (!test.hitTestPoint(MovieClip(root).char.x-speed, MovieClip(root).char.y, true))
{
MovieClip(root).char.x -= speed;
x = x+speed; //moving the background
}
}
if (upArrow) {
if (!test.hitTestPoint(MovieClip(root).char.x, MovieClip(root).char.y-speed, true))
{
MovieClip(root).char.y -= speed;
y = y+speed; //moving the background
}
}
if (downArrow) {
if (!test.hitTestPoint(MovieClip(root).char.x, MovieClip(root).char.y+speed, true))
{
MovieClip(root).char.y += speed;
y = y-speed; //moving the background
}
}
It's been a while so some of this stuff I really don't remember, but from what I can see, I check if adding the speed of my character will make it become collided with the wall. If that happens, I do not move the character even if I do seemingly have enough space. I think that is pretty much it.
Hope it helps.