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.
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 am in the process of making a platformer in AS3. However, one thing im struggling with is how to manage slope detection. Preferably id like something similar to that of games like fancy pants adventures, but id really prefer not to use an external thing such as Box2D or CDK, because both of which confuse me greatly, and id generally prefer just to not have one. All my attempts have had the problem that i can get it to work with some slopes but not all (e.g character manages up one slope, but falls through the other) then when i change it to suit the other, it doesnt suit the first one (e.g player manages the second slope, but bounces up and down crazily on the second...
So, any help would be greatly appreciated...
Thanks.
Code is as follows.
//var setup
var leftPressed: Boolean = false;
var rightPressed: Boolean = false;
var upPressed: Boolean = false;
var downPressed: Boolean = false;
var leftBumping: Boolean = false;
var rightBumping: Boolean = false;
var upBumping: Boolean = false;
var downBumping: Boolean = false;
var lowerleftBumping: Boolean = false;
var lowerrightBumping: Boolean = false;
var leftBumpPoint: Point = new Point(-30, -87);
var rightBumpPoint: Point = new Point(30, -87);
var lowerleftBumpPoint: Point = new Point(-32, -2);
var lowerrightBumpPoint: Point = new Point(32, -2);
var upBumpPoint: Point = new Point(0, -174);
var downBumpPoint: Point = new Point(0, 0);
var scrollX: Number = -4;
var scrollY: Number = -68;
var ySpeed: Number = 0;
var xSpeed: Number = 0;
var speedConstant: int = 5;
var maxSpeedConstant: Number = 30;
var frictionConstant: Number = 0.9;
var gravityConstant: Number = 2;
var jumpConstant: Number = -45;
//game
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
stage.addEventListener(Event.ENTER_FRAME, loop);
function keyDownHandler(e: KeyboardEvent): void {
if (e.keyCode == Keyboard.LEFT) {
leftPressed = true;
} else if (e.keyCode == Keyboard.RIGHT) {
rightPressed = true;
} else if (e.keyCode == Keyboard.UP) {
upPressed = true;
} else if (e.keyCode == Keyboard.DOWN) {
downPressed = true;
}
}
function keyUpHandler(e: KeyboardEvent): void {
if (e.keyCode == Keyboard.LEFT) {
leftPressed = false;
} else if (e.keyCode == Keyboard.RIGHT) {
rightPressed = false;
} else if (e.keyCode == Keyboard.UP) {
upPressed = false;
} else if (e.keyCode == Keyboard.DOWN) {
downPressed = false;
}
}
function loop(e: Event): void {
if (back.hitTestPoint(player.x + leftBumpPoint.x, player.y + leftBumpPoint.y, true)) {
trace("leftBumping");
leftBumping = true;
} else {
leftBumping = false;
}
if (back.hitTestPoint(player.x + rightBumpPoint.x, player.y + rightBumpPoint.y, true)) {
trace("rightBumping");
rightBumping = true;
} else {
rightBumping = false;
}
if (back.hitTestPoint(player.x + upBumpPoint.x, player.y + upBumpPoint.y, true)) {
trace("upBumping");
upBumping = true;
} else {
upBumping = false;
}
if (back.hitTestPoint(player.x + downBumpPoint.x, player.y + downBumpPoint.y, true)) {
trace("downBumping");
downBumping = true;
} else {
downBumping = false;
}
if (back.hitTestPoint(player.x + lowerleftBumpPoint.x, player.y + lowerleftBumpPoint.y, true)) {
trace("lowerrightBumping");
lowerleftBumping = true;
} else {
lowerleftBumping = false;
}
if (back.hitTestPoint(player.x + lowerrightBumpPoint.x, player.y + lowerrightBumpPoint.y, true)) {
trace("lowerrightBumping");
lowerrightBumping = true;
} else {
lowerrightBumping = false;
}
if (leftPressed) {
xSpeed -= speedConstant;
} else if (rightPressed) {
xSpeed += speedConstant;
}
if (leftBumping) {
if (xSpeed < 0) {
xSpeed *= -0.5;
}
}
if (rightBumping) {
if (xSpeed > 0) {
xSpeed *= -0.5;
}
}
if (upBumping) {
if (ySpeed < 0) {
ySpeed *= -0.5;
}
}
if (downBumping) {
if (ySpeed > 0) {
ySpeed = 0; //set the y speed to zero
}
if (upPressed) {
ySpeed = jumpConstant;
}
} else {
ySpeed += gravityConstant;
}
if (xSpeed > maxSpeedConstant) { //moving right
xSpeed = maxSpeedConstant;
} else if (xSpeed < (maxSpeedConstant * -1)) { //moving left
xSpeed = (maxSpeedConstant * -1);
}
xSpeed *= frictionConstant;
ySpeed *= frictionConstant;
if (Math.abs(xSpeed) < 0.5) {
xSpeed = 0;
}
scrollX -= xSpeed;
scrollY -= ySpeed;
back.x = scrollX;
back.y = scrollY;
if (scrollY < -770) {
scrollX = -4;
scrollY = -68;
ySpeed=0
xSpeed=0
}
}
If I was forced to not use the love of my life (Box2D) then I suppose I would play around with hitTestObject and do some math on the angle of any of my slopes to generate the rate at which they would move to start. This question is a bit broad and I think the community here is more for specific problems and not architecture brainstorming.
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;
}
}
My player stops moving when two keys are pressed at the same time. But the animation still moves. For example, if I press up and down at the same time or right and left at the same time.
On key down event listener:
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
}
On key up event listener:
if (event.keyCode == Keyboard.D)
{
isRight = false
gotoAndStop(1);
}
if (event.keyCode == Keyboard.A)
{
isLeft = false
gotoAndStop(1);
}
if (event.keyCode == Keyboard.W)
{
isUp = false
gotoAndStop(1);
}
if (event.keyCode == Keyboard.S)
{
isDown = false
gotoAndStop(1);
}
On enterframe:
if (isRight == true)
{
x += 5;
play();
}
if (isLeft == true )
{
x -= 5;
play();
}
if (isUp == true)
{
y -= 5;
play();
}
if (isDown == true)
{
y += 5;
play();
}
If players goes x -= 1 and x += 1 it basically moves x += 0 overall. We can easily check that and stop animation in needed:
var iP:Point = new Point(x,y);//try to avoid creating new objects on frame interval
if (isRight) x += 5;
if (isLeft) x -= 5;
if (isUp) y -= 5;
if (isDown) y += 5;
if(!Point.distance(iP,new Point(x,y)) goToAndStop(1);
else play();
I don't see any checks to see if more than 1 key is being pressed?
surely you should introduce something like a keycount into the enterframe:
var count:uint = 0;
if (isRight == true){
count++
x += 5;
}
if (isLeft == true ){
count++;
x -= 5;
}
if (isUp == true){
count++;
y -= 5;
}
if (isDown == true){
count++
y += 5;
}
if (count > 1) {
isRight = isLeft = isUp = isDown = false;
gotoAndStop(1);
} else {
play();
}
Working on a maze game. When the leftkey is pressed the movieclip (char) should turn 90 degrees to the left.
Correct me if i'm wrong but I thought I could use this code;
char.scaleX *= -1;
However, the most important thing is that the character doesnt go through the walls of the maze.
And I think thats my problem for implementing the code above.
Because it doesnt work properly when i put in here;
if(!mazehit) {
char.y += speed;
char.scaleX *= -1;
}
My question to you is, where do I have to put the code to flip the movieclip?
var leftArrow, rightArrow, upArrow, downArrow:Boolean;
var speed:Number = 4;
var charRadius:Number = 10;
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.ENTER_FRAME, everyFrame);
function keyPressed(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.LEFT) {
leftArrow = true;
}
if (event.keyCode == Keyboard.RIGHT) {
rightArrow = true;
}
if (event.keyCode == Keyboard.UP) {
upArrow = true;
}
if (event.keyCode == Keyboard.DOWN) {
downArrow = true;
}
}
function keyReleased(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.LEFT) {
leftArrow = false;
}
if (event.keyCode == Keyboard.RIGHT) {
rightArrow = false;
}
if (event.keyCode == Keyboard.UP) {
upArrow = false;
}
if (event.keyCode == Keyboard.DOWN) {
downArrow = false;
}
}
function everyFrame(event:Event):void {
var mazehit:Boolean = false;
if (leftArrow) {
for(var i:int = 0; i < speed; i++) {
if(bounds.hitTestPoint(char.x - charRadius - i, char.y, true)) {
mazehit = true;
break;
}
}
if(!mazehit) {
char.x -= speed;
}
} else if (rightArrow) {
for(var j:int = 0; j < speed; j++) {
if(bounds.hitTestPoint(char.x + charRadius + j, char.y, true)) {
mazehit = true;
break;
}
}
if(!mazehit) {
char.x += speed;
}
} else if (upArrow) {
for(var k:int = 0; k < speed; k++) {
if(bounds.hitTestPoint(char.x, char.y - charRadius - k, true)) {
mazehit = true;
break;
}
}
if(!mazehit) {
char.y -= speed;
}
} else if (downArrow) {
for(var m:int = 0; m < speed; m++) {
if(bounds.hitTestPoint(char.x, char.y + charRadius + m, true)) {
mazehit = true;
break;
}
}
if(!mazehit) {
char.y += speed;
}
}
}
thank you for your time
I would update the direction depending on the speed:
char.scaleX = (speed > 0) ? 1 : -1;
Or, by the keys that have been pressed:
if(keyLeft && !keyRight)
{
char.scaleX = -1;
}
else if(keyRight && !keyLeft)
{
char.scaleX = 1;
}
else
{
// keep current direction
}