I have some code whereby I want a symbol (just a square atm) to bounce around inside the stage. Occasionally however, it gets stuck on the edges. Any advice on how to fix this?
Everything else works fine, including the inertial motion.
package {
import flash.display.MovieClip;
import flash.events.*
import flash.ui.Keyboard
public class Unit extends MovieClip {
var velocityX:Number = 1;
var velocityY:Number = 1;
var accellerationX:Number = 1;
var accellerationY:Number = 1;
var bounciness:Number = 1;
var maxSpeed:Number = 10;
public function Unit(){
Key.initialize(stage);
addEventListener("enterFrame", move);
}
private function move(e:Event){
accellerate()
if ((this.x<10)||(this.x>780)){
velocityX *= -1;
if (velocityX>0){
velocityX -= bounciness;
}
if (velocityX<0){
velocityX += bounciness;
}
this.x += velocityX;
}
else{
this.x += velocityX;
}
if ((this.y<10)||(this.y>520)){
velocityY *= -1;
if (velocityY>0){
velocityY -= bounciness;
}
if (velocityY<0){
velocityY += bounciness;
}
this.y += velocityY;
}
else {
this.y += velocityY;
}
}
private function accellerate(){
if (Math.abs(velocityY) < maxSpeed){
if (Key.isDown(Keyboard.UP)){
velocityY -= accellerationY;
trace("Accellerating UP");
}
if (Key.isDown(Keyboard.DOWN)){
velocityY += accellerationY;
trace("Accellerating DOWN");
}
}
if (Math.abs(velocityX) < maxSpeed){
if (Key.isDown(Keyboard.RIGHT)){
velocityX += accellerationX;
trace("Accellerating RIGHT");
}
if (Key.isDown(Keyboard.LEFT)){
velocityX -= accellerationX;
trace("Accellerating LEFT");
}
}
if (Key.isDown(Keyboard.SPACE)){
velocityX = 0;
velocityY = 0;
}
}
}
}
Your problem is like the following:
if ((this.x<10)||(this.x>780)){
velocityX *= -1;
You toggle the volocityX, but what is likely happening is on the next frame, it still meets the if condition (hasn't moved far enough the other direction) so it's just going back and forth every frame from -1 to 1.
Do something like this instead:
if(this.x < 10 && velocity == -1) velocity = 1; //If it's near the left edge, and still moving to the left, change direction
if(this.x > 780 && velocity == 1) velocity = -1;
This way, you are only flipping the direction when it's going the wrong way.
Repeat for the velocityY stuff
Related
I have a set-up of 3 horizontal rows with a button aligned to each of them and a character (centered to each row) that I want to move between these rows (think of Little Big Planet). I was able to program it so the character moves between the 3 rows and has a set scale when it does, but I want to see the character actually moving between the points; not just watch it teleport to the location. I've tried everything I can think of: Loops, Boolean on/off, some velocity/distance/difference shenanigans, etc., but I'm having no success getting it to move at a button click and continue moving until it reaches its point. I'm also not sure if it can be set-up to scale incrementally until it reaches a desired end scale size or not. I saw a slightly similar problem asked on a site, but solution they gave uses the Point class and a lot of math, and I have never had success getting my Flash to use Points. Any suggestions would be appreciated.
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main_Test_5 extends MovieClip
{
private var cam:MovieClip = new MovieClip();
private var player:Player = new Player();
private var topPosition:uint = 170;
private var centerPosition:uint = 270;
private var bottomPosition:uint = 370;
private var UI:UserInterface = new UserInterface();
private var testBackground:TestBackground = new TestBackground();
public function Main_Test_5():void
{
player.x = 100;
player.y = 370;
cam.addChild(player);
addChild (UI);
// add event listeners
stage.addEventListener(Event.ENTER_FRAME, checkEveryFrame);
UI.topButton.addEventListener(MouseEvent.CLICK, topButtonClick);
UI.centerButton.addEventListener(MouseEvent.CLICK, centerButtonClick);
UI.bottomButton.addEventListener(MouseEvent.CLICK, bottomButtonClick);
addChild (cam);
}
public function checkEveryFrame(event:Event):void
{
cam.x -= player.x - player.x;
cam.y -= player.y - player.y;
}
public function topButtonClick (event:MouseEvent):void
{
trace ("Top Click");
if (player.y > topPosition) // 170, player.y starts at 370
{
player.y -= 100;
}
else if (player.y <= topPosition)
{
player.y = topPosition;
}
if (player.y == topPosition)
{
player.scaleY = 0.8;
player.scaleX = 0.8;
}
else if (player.y != topPosition)
{
player.scaleY = 0.9;
player.scaleX = 0.9;
}
}
public function centerButtonClick (event:MouseEvent):void
{
trace ("Center Click");
if (player.y > centerPosition) // 270
{
player.y -= 100;
}
if (player.y < centerPosition)
{
player.y += 100;
}
if (player.y == centerPosition)
{
player.scaleY = 0.9;
player.scaleX = 0.9;
}
}
public function bottomButtonClick (event:MouseEvent):void
{
trace ("Bottom Click");
if (player.y < bottomPosition) // 370
{
player.y += 100;
}
if (player.y >= bottomPosition)
{
player.y = bottomPosition;
}
if (player.y == bottomPosition)
{
player.scaleY = 1;
player.scaleX = 1;
}
else if (player.y != bottomPosition)
{
player.scaleY = 0.9;
player.scaleX = 0.9;
}
}
}
}
Sounds like you'd like something simple. So I would suggest using a Tweening library. The most prolific of which is Greensocks TweenLite, which is now part of their Animation Platform
Using tweenlite, you would just do the following:
In place of:
player.y += 100;
You would do:
TweenLite.to(player, 1,{y: player.y + 100, ease: Quad.EaseInOut});
This would tween (move gradually over time) your player object from it's current position to the specified y (player.y + 100). It would do it over 1 second and with a nice in and out ease.
You can add more properties to the tween (scaleX/Y, x) anything really.
Do note, there are many Tweening platform alternatives, including one baked into Flash Professional. TweenLite is not free to use if you charge your end users a fee for your application. Be sure to review their license if you use it commercially.
Ok, so I have an object on the stage that moves on the "world" movieclip. I'm trying to make it so that when you're moving right. If the movieclip inside the moving movieclip("dude") called hitD collides with the walls in world, the dude stops moving forward.
Screen shots if it might help.
General stage dude object selected
http://prntscr.com/5bgjfq the world is everything but the ball
http://prntscr.com/5bgjuh
hitD
If anyone has any way they can modify these collision physics since my current code is sketchy as hell, all suggestions and ideas are welcome.
var started:Boolean;
const NUMLEVELS = 3;
var status:String;
stage.focus = stage;
if (! started)
{// Only ever do this once!
status = "falling";
started = true;
var speedX:Number = 5;
var speedY:Number = 0;
var topSpeedY:Number = 50;
var start_x:Number = dude.x;
var start_y:Number = dude.y;
var keysDown:Object = new Object();
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener( Event.DEACTIVATE, appDeactivate );
dude.addEventListener(Event.ENTER_FRAME, moveDude);
var W:Number = 15;
var snows:Array = new Array();
}
for (var b:int = 0; b < 50; b++)
{
var snow:Snow = new Snow();
snows.push(snow);
addChild(snow);
}
function cleanup()
{
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.removeEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.removeEventListener( Event.DEACTIVATE, appDeactivate );
dude.removeEventListener(Event.ENTER_FRAME, moveDude);
}
function keyIsDown(key:uint):Boolean
{
return Boolean(key in keysDown);
}
function keyPressed(e:KeyboardEvent):void
{
keysDown[e.keyCode] = true;
}
function keyReleased(e:KeyboardEvent):void
{
delete keysDown[e.keyCode];
}
function appDeactivate( event:Event ):void
{
// Get rid of all keypress info when app loses focus
keysDown=new Object();
}
function moveDude(e:Event):void
{
var obj:Object = e.target; //setting dude as object
// for now, if you get off the top of the screen you win
if (obj.y < 0)
{
cleanup();
nextScene();
return;
}
// if character dies, restart
if (obj.y > stage.stageHeight + 100)
{
gotoAndStop(1);
obj.x = start_x;
obj.y = start_y;
}
if (death!=null)
{
if (obj.hitTestObject(death))
{
trace("Dead");
}
}
if (status=="falling")
{
speedY++;
if (speedY>topSpeedY)
{
speedY = topSpeedY;
}
for (i = 0; i<2*speedY; i++)
{
obj.y++;
if (world.hitTestPoint(obj.x - obj.width / 2,obj.y,true) || world.hitTestPoint(obj.x + obj.width / 2,obj.y,true))
{
status = "ground";
break;
}
}
}
else if (status == "jumping")
{
speedY--;
for (i = 0; i<2*speedY; i++)
{
obj.y--;
if (world.hitTestPoint(obj.x - obj.width / 2,obj.y - obj.height,true) || world.hitTestPoint(obj.x + obj.width / 2,obj.y - obj.height,true))
{
speedY = 0;
break;
}
}
if (speedY==0)
{
status = "falling";
}
}
else if (status == "ground")
{
if (! world.hitTestPoint(obj.x - 8,obj.y,true) && ! world.hitTestPoint(obj.x + 8,obj.y + 4,true))
{
speedY = 0;
status = "falling";
}
if (keyIsDown(Keyboard.UP))
{
status = "jumping";
speedY = 10;
}
}
if (keyIsDown(Keyboard.DOWN)&&status=="ground")
{
dude.gotoAndStop("duck");
}
else
{
if (keyIsDown(Keyboard.SHIFT))
{
speedX = 10;
}
else
{
speedX = 5;
}
if (keyIsDown(Keyboard.LEFT))
{
for (i = 0; i<speedX; i++)
{
obj.x--;
dude.ball.rotation--; //dude.ball is a movieclip similar to dude.hitD, it spins when you move.
if (world.hitTestPoint(obj.x - obj.width / 2 + 4,obj.y - 8,true) || world.hitTestPoint(obj.x - obj.width / 2,obj.y - obj.height + 8,true))
{
dude.ball.rotation++;
obj.x++;
break;
}
}
}
else if (keyIsDown(Keyboard.RIGHT))
{
//dude.gotoAndStop("right");
//obj.scaleX = 1;
for (i = 0; i<speedX; i++)
{
obj.x++;
dude.ball.rotation++;
// The number in obj.y-4 affects the climbing ability
if (status == "ground")
{
//dude.height+= 0.1;
//dude.width += 0.1;
}//so here I'm checking if it hits the lower corner or top right corner or hitD
if (world.hitTestPoint(dude.hitD.x + obj.hitD.width/2 , obj.hitD.y,true) || world.hitTestPoint(obj.hitD.x + obj.hitD.width/2,obj.hitD.y - obj.hitD.height ,true))
//if (world.hitTestObject(obj))
{
dude.ball.rotation--;
obj.x--;
break;
}
}
}
dude.gotoAndStop(1);
}
while (status == "ground" && (world.hitTestPoint(obj.x-8, obj.y-1, true) || world.hitTestPoint(obj.x+8, obj.y-1, true)))
{
obj.y--;
}
const BORDER = 50;
var diff:int;
// Check right border:
diff = obj.x + BORDER - stage.stageWidth;
if (diff>0 && world.x>=stage.stageWidth-world.width)
{
obj.x -= diff;
world.x -= diff;
background1.x -= diff;
if (death != null)
{
death.x -= diff;
}
}
// Check left border:
diff = obj.x - BORDER;
if (diff<0 && world.x<=0)
{
obj.x -= diff;
world.x -= diff;
background1.x -= diff;
if (death != null)
{
death.x -= diff;
}
}
// Check bottom border:
diff = obj.y + BORDER - stage.stageHeight;
if (diff>0)
{
obj.y -= diff;
world.y -= diff;
background1.y -= diff;
if (death != null)
{
death.y -= diff;
}
}
// Check top border:
diff = obj.y - BORDER;
if (diff<0)
{
obj.y -= diff;
world.y -= diff;
background1.y -= diff;
if (death != null)
{
death.y -= diff;
}
}
if (obj.x > stage.stageWidth - 25)
{
if (currentFrame<NUMLEVELS)
{
gotoAndStop(currentFrame+1);
obj.x = 25;
}
else
{
obj.x = stage.stageWidth - 25;
}
}
else if (obj.x<25)
{
if (currentFrame>1)
{
gotoAndStop(currentFrame-1);
obj.x = stage.stageWidth - 25;
}
else
{
obj.x = 25;
}
}
}
Thanks in advance for any help you can provide :)
For player physics, it's more clear approach to make a central ENTER_FRAME handler function that just for calculating the transformations to be applied to player.
You can still get information from out, but you just process the final output there. Else, it could be problematic, especially when things gets more complex and when you want to add some more feature.(e.g. Imagine in the future, you wanted to add fans on the ground that blows air up, and player have to rise when on them. There you have a lot to change, and probably with many problems.
For collision detection, this function will provide you this information: to which direction(s) the player can't go with variables 'UpColl', 'DownColl', 'Right Coll' and 'LeftColl'.
Then you can refer to this information from your main function that applies the transformation to your player. I'll give example to that also below.
function collEveryFrame(event:Event):void
{
// capture player positions
player_x = WORLD.player.x;
player_y = WORLD.player.y;
// the movie clip object where you store your solid objects. Remember, ALL MovieClip objets inside this MovieClip will taken as solid objects in your game, and regardless their shape, their boundingBox will be taken as collison. So they will all be square.
collContainer = WORLD.cW;
// your player's collision object
playerColl = WORLD.player;
// RIGHT SQUARE COLLISION DETECTION
for (var i:int; i < collContainer.numChildren; i++)
{
// Check if any collision object colliding with player
if (playerColl.hitTestObject(collContainer.getChildAt(i)))
{
// One collision detected. Check 'from which side' does the player colliding with the object;
if (collContainer.getChildAt(i).y > playerColl.y + playerColl.height - p1MoveSpeed)
{
playerColl.y = collContainer.getChildAt(i).y - playerColl.height;
DownColl = true;
}
else if (collContainer.getChildAt(i).y + collContainer.getChildAt(i).height < playerColl.y + p1MoveSpeed)
{
playerColl.y = collContainer.getChildAt(i).y + collContainer.getChildAt(i).height;
UpColl = true;
}
else if (collContainer.getChildAt(i).x + collContainer.getChildAt(i).width < playerColl.x + p1MoveSpeed)
{
playerColl.x = + collContainer.getChildAt(i).x + collContainer.getChildAt(i).width;
LeftColl = true;
}
else if (collContainer.getChildAt(i).x > playerColl.x + playerColl.width - p1MoveSpeed)
{
playerColl.x = + collContainer.getChildAt(i).x - playerColl.width;
RightColl = true;
}
}
}
// RIGHT SQUARE COLLISION DETECTION [End]
}
Transformation function;
function playerMovement(event:Event):void
{
// (apply this for all sides)
// if nothing keeps player from going right;
if (! RightColl)
{
// Apply everything currently pushing the player to right
if (keyIsDown(Keyboard.RIGHT))
{
movement_Right = 15;
}else{
movement_Right = 0;
}
// example fictional wind function returns wind speed
windSpeed = getWindSpeed();
player.x += movement_Right + windSpeed + etc + etc;
// say windSpeed is -5 (Wind is coming from right, so pushing the player to left)
// so if user pressing right arrow key, player will move to right 10px for every frame, else 5px to left, etc.
}
}
In this way, everything about physics will be easy to implement.
For example, when calculating the movement to down, add gravity and jump etc.
What code should I put in here to make my ship stay in the stage?
My ship keeps going off the stage when I press the keys and it goes too far. How do I get it to bump into walls and make it stay on the stage?
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.ui.Keyboard;
public class Ship extends MovieClip{
var velocity:Number;
var shootLimiter:Number;
var health:Number;
var maxHealth:Number;
function Ship(){
velocity = 10;
shootLimiter = 0;
health = 100;
maxHealth = 100;
addEventListener("enterFrame", move);
}
function kill(){
var explosion = new Explosion();
stage.addChild(explosion);
explosion.x = this.x;
explosion.y = this.y;
removeEventListener("enterFrame", move);
this.visible = false;
Game.gameOver();
}
function takeDamage(d){
health -= d;
if(health<=0){
health = 0;
kill();
}
Game.healthMeter.bar.scaleX = health/maxHealth;
}
function move(e:Event){
shootLimiter += 1;
if(Key.isDown(Keyboard.D)){
this.x = this.x + velocity;
}
if(Key.isDown(Keyboard.A)){
this.x = this.x - velocity;
}
if(Key.isDown(Keyboard.W)){
this.y = this.y - velocity;
}
if(Key.isDown(Keyboard.S)){
this.y = this.y + velocity;
}
if(Key.isDown(Keyboard.SPACE) && shootLimiter > 8){
shootLimiter = 0;
var b = new Bullet();
stage.addChild(b);
b.x = this.x + 40;
b.y = this.y + -25;
}
if(shield.visible == true){
shield.alpha -= 0.0005;
if(shield.alpha == 0){
shield.visible = false;
shield.alpha = 1;
}
}
}
}
}
Your code is hard to fix as it is, but I'll give you an answer in pseudo, so you could think on how to implement it to fit in your project. Your ship is going out of the frame because it has no notion of where to stop. Lets say the ship x and y coordinates are taken from the upper left corner of the sprite, as it is in actionscript, then, every time your ship moves to the left, you must consider the following:
if(Key.isDown(Keyboard.A)){
var futureX:Number = this.x - velocity;
if (futureX <= 0){ //your ship has reached the left border of the screen
this.x = 0;
} else {
this.x = futureX;
}
}
things get a little more complicated when you're checking for the right or bottom border of the screen, as you need to consider the size of your stage and the size of your sprite in the calculations:
if(Key.isDown(Keyboard.S)){
var futureY:Number = this.y + velocity;
if (futureY + this.height >= Stage.stageHeight){
this.y = Stage.stageHeight - this.height;
} else {
this.y = futureY;
}
}
The solution for the top and right borders are trivial after this.
The question is clear. Character is stable on the stage and background and ground is moving. But when character hits the ground, it bounces again and again. Here is the code. how can i solve it? When i move the character its working perfect but when the moving object is ground bouncing problem happens.
here is the problem : http://www.swfcabin.com/open/1391814250
public function controller():void
{
if (rightKey || leftKey || jumpKey)
{
if (rightKey)
{
if (jumpWalk || canJump)
{
hero.gotoAndStop(2);
hero.scaleX = 1;
xSpeed -= speed;
}
}
if (leftKey)
{
if (jumpWalk || canJump)
{
hero.gotoAndStop(2);
hero.scaleX = -1;
xSpeed += speed;
}
}
if (jumpKey && canJump)
{
ySpeed += 15;
canJump = false;
}
}
else
{
hero.gotoAndStop(1);
}
if(!canJump){
hero.gotoAndStop(3);
}
ySpeed -= gravity;
if(ySpeed >10){
ySpeed = 10;
}
else if(ySpeed < -10){
ySpeed = -10;
}
if(xSpeed>10){
xSpeed = 10
}
else if(xSpeed < -10){
xSpeed = -10;
}
xSpeed *= 0.8;
level.x += xSpeed;
level.y += ySpeed;
}// controller function
public function loop(event:Event):void
{
controller();
while(level.hitTestPoint(hero.x , hero.y + hero.height/2 -1 - ySpeed , true)){
trace(ySpeed +"dasd");
ySpeed ++;
canJump = true;
} }
Here is what is happening now: when you are embedded in terrain, you are increasing the ySpeed -- the upward momentum -- until one 'tick' pulls the character out of the ground. But then the character is flying upward, because you increased their upward momentum. They still have that upward momentum until gravity pulls them back down, so they will keep 'bouncing'. To fix this, do the following:
Instead of ySpeed ++; in the main loop, try level.y++; This would represent pulling the hero out of the terrain when he is embedded (or actually pulling the terrain down, since your character is stationary), instead of changing his momentum to get him out.
You should also add ySpeed = 0; in there. That would represent losing all of your y-momentum when you hit the ground.
So your main loop would look like this:
public function loop(event:Event):void
{
controller();
while(level.hitTestPoint(hero.x , hero.y + hero.height/2 -1 - ySpeed , true)){
trace(ySpeed +"dasd");
level.y++;
ySpeed = 0;
canJump = true;
} }
package com.basics.stick
{
import flash.display.MovieClip;
import flash.display.Stage;
import com.basics.senocular.utils.KeyObject;
import flash.ui.Keyboard;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class StickMan extends MovieClip
{
private var stageRef:Stage;
private var key:KeyObject;
private var speed:Number = 2;
private var vx:Number = 0;
private var vy:Number = 0;
private var friction:Number = 0.93;
private var maxspeed:Number = 8;
private var fireTimer:Timer;
private var canFire:Boolean = true;
public function StickMan(stageRef:Stage)
{
this.stageRef = stageRef;
key = new KeyObject(stageRef);
fireTimer = new Timer(300,1);
fireTimer.addEventListener(TimerEvent.TIMER, fireTimerHandler, false, 0, true);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function fireTimerHandler(e:TimerEvent):void
{
canFire = true;
}
private function fireBullet():void
{
if (canFire)
{
stageRef.addChild(new Bullet(stageRef,x+vx+35, y+10));
canFire = false;
fireTimer.start();
}
}
public function loop(e:Event):void
{
if (key.isDown(Keyboard.LEFT))
{
vx -= speed;
}
else if (key.isDown(Keyboard.RIGHT))
{
vx += speed;
}
else
{
vx *= friction;
}
if (key.isDown(Keyboard.UP))
{
vy -= speed;
}
else if (key.isDown(Keyboard.DOWN))
{
vy += speed;
}
else
{
vy *= friction;
}
if (key.isDown(Keyboard.SPACE))
{
fireBullet();
}
x += vx;
y += vy;
if (vx > maxspeed)
{
vx = maxspeed;
}
else if (vx<-maxspeed)
{
vx = - maxspeed;
}
if (vy > maxspeed)
{
vy = maxspeed;
}
else if (vy<-maxspeed)
{
vy = - maxspeed;
}
if (x > stageRef.stageWidth)
{
x = stageRef.stageWidth;
vx = - vx;
}
else if (x<0)
{
x = 0;
vx = - vx;
}
if (y > stageRef.stageHeight)
{
y = stageRef.stageHeight;
vy = - vy;
}
else if (y<0)
{
y = 0;
vy = - vy;
}
}
}
}
What i want is when i press the up button, not just go up, but jump, and then come down to a specific y. I searched online, but most of the tutorials or other users place the code in the character. However what i want is to amend the code above, and make the character jump. Any guidance or whatsoever is really welcome.
thanx in advance for your time! :)
Your logic for vy should be different than vx. What you need to do for vy is suddenly set it to a fairly large negative value, and then after that constantly add a small value to simulate gravity. That's what gravity is: a rate of change (acceleration) of vertical speed.
You already know how to use flags, so you can make a flag for jumping, just like you did for canFire.
if (canJump)
{
if(key.isDown(Keyboard.UP))
{
vy = -8; // for example this value, notice that it is assignment and not "-="
groundy = y; // this a class private var, to remember the ground level
canJump = false;
}
else if (key.isDown(Keyboard.DOWN))
{
// Forget about this, this can be erased
// vy += speed;
}
else
{
// Also forget about this, it can be erased
//vy *= friction;
}
}
else
{
vy += 0.2; // an example value that you can tweak. this simulates gravity
// The character is going down and now hits the ground
if(y > groundy) {
vy = 0;
y = groundy;
canJump = true;
}
}
// ...
x += vx;
y += vy;
// ...
The code above isn't really tested, but it should work, this is basic gameplay programming and is really just about basic computational physics, like speed and acceleration.
I suppose that this is the Mario platformer effect (on ice, because of the way you handle vx) you want to get in your game. Of course the logics will be really different if you want a gameplay like Final Fight (walking vertically and horizontally and also jumping).