I'm trying to make a pseudo 3D collision with multiple walls. It works to an extent:
I can collide with the sides of each wall
but only on one of the walls, if I were to go to the top, It goes behind the rectangle like this but on the second rectangle, I go above it like this I don't why this is happening (I am a beginner in AS3). Using trace, it says that the player is at layer 0 while the wall is at layer 2, but the ball still goes above the wall.
edit: I'm using flashdevelop incase that changes anything
Edit: Changed code, it works fine, but ignores the second wall, it prints it's name but doesn't change the boolean
for each (var wall in WallsList)
{
trace(wall.name)
if (wall.hitTestPoint(Character.x - hitRad+.995, Character.y, true)) //col right
{
Character.x+=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x + hitRad-.995, Character.y, true)) //col left
{
Character.x-=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x , Character.y- hitRad+25, true)) //col bottom
{
Character.y+=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x, Character.y+hitRad-25, true)) //col top
{
Character.y -= CharacterSpeed;
}
if (wall.hitTestPoint(Character.x, Character.y+hitRad, true)) // col top #2
{
trace(wall.name) // prints for both walls
Top = true; // only changes for 1 wall
}
if (!wall.hitTestPoint(Character.x, Character.y+hitRad, true))
{
Top = false;
}
}
Bring wall object above the ball:
setChildIndex(wallObject, this.numChildren - 1);
Related
So I created a nice collision system shown here. Now I have my own character sprite, which has messed up the collision on all sides.
edit: because people are misunderstand what I want, I WANT it to overlap on the bottom and top, it gives it a 3D effect. My problem is that it's colliding incorrectly with the bitmap
I've tried using the pixel perfect collision system but I have a problem with it:
It only detects collision right at the edge, as you can see in the video, the ball can go slightly in front and behind the wall like it wasn't just a flat plane.
code responsible for the current collision (it did have some other stuff but that's been removed):
for each (var wall in Walls)
{
if (wall.hitTestPoint(Character.x, Character.y, true)) //col right
{
Character.x+=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x, Character.y, true)) //col left
{
Character.x-=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x , Character.y, true)) //col bottom
{
Character.y+=CharacterSpeed;
}
if (wall.hitTestPoint(Character.x, Character.y, true)) //col top
{
Character.y -= CharacterSpeed;
}
}
That is correct (and I mean that's what the code does) and that effect depends on framerate as well.
The principle is easy to understand. ex: You move an object by 5 pixels, the colliding object is 3 pixels away, when you test for collision you have an overlap of 2 pixels. To correct this you need what's called a TOI (time of impact) algorithm.
As of right now there's no fixing your code because you apply a motion is the inverse way it's supposed to work. You move first then you test while the correct way is you test then you move. For example:
you are about to move the object by x pixels.
test if the object + x pixels will collide.
if it will collide calculate by how much you should move it then move it by x pixels - corrected pixels.
if it will not collide then move it by x pixels.
As you see you do the opposite:
move by x pixels.
test for collision.
The result is overlapping objects.
What you can do as a hack without changing your code is calculate the overlapping and then correct the object position.
you can try draw your objects to a BitmapData using BitmapData.draw method, and than use BitmapData.hittest, here a sample:
import flash.display.BitmapData;
import flash.geom.Point;
var myBitmapData:BitmapData = new BitmapData(100, 80, false, 0x00CCCCCC);
var mc_1:MovieClip = this.createEmptyMovieClip("mc", this.getNextHighestDepth());
mc_1.attachBitmap(myBitmapData, this.getNextHighestDepth());
var mc_2:MovieClip = createRectangle(20, 20, 0xFF0000);
var destPoint:Point = new Point(myBitmapData.rectangle.x, myBitmapData.rectangle.y);
var currPoint:Point = new Point();
mc_1.onEnterFrame = function() {
currPoint.x = mc_2._x;
currPoint.y = mc_2._y;
if(myBitmapData.hitTest(destPoint, 255, currPoint)) {
trace(">> Collision at x:" + currPoint.x + " and y:" + currPoint.y);
}
}
mc_2.startDrag(true);
function createRectangle(width:Number, height:Number, color:Number):MovieClip {
var depth:Number = this.getNextHighestDepth();
var mc:MovieClip = this.createEmptyMovieClip("mc_" + depth, depth);
mc.beginFill(color);
mc.lineTo(0, height);
mc.lineTo(width, height);
mc.lineTo(width, 0);
mc.lineTo(0, 0);
return mc;
}
Hey everyone this one has me stumped. So I have an Array of Movie clips called sharkthat are added to the stage from either the left or the right side of the stage. Now when they are added I have them move in either the positive or negative x position, so in a Horizontal line. But to make the effect that the player is moving forward in a stream of water and all the other objects are passing the player I also have the array of shark move clips moving in the positive y position so moving vertically downwards. But when I do this have the values in my ENTER_FRAME the shark movie clips in the array appear to be moving Diagonal which is what I don't want at all. Does anyone know how to fix this to have the Movie clip move downwards and also in a straight line across the screen.
Here is what I have so far in my shark class:
private function startPosition():void
{
//Pick the frames for start position
var nRandom:Number = randomNumber(1, 2);
//Setup goto and stop on timeline
this.gotoAndStop(nRandom);
//Pick a random speed
nSharkSpeed = randomNumber(3, 5);
//Pick a random number for start position
var nLeftOrRight:Number = randomNumber(1, 2);
//If our nLeftOrRIght == 1 start on the left side
if (nLeftOrRight == 1)
{
//Start shark on left side and move to right
this.x = (stage.stageWidth / 2) - 240;
sSharkDirection = "R";
}else
{
//Start shark on right side and move to left
this.x = (stage.stageWidth / 2) + 240;
sSharkDirection = "L";
}
//Set y position
this.y = (stage.stageHeight / 2) - 400;
//Move our shark
startMoving();
}
private function startMoving():void
{
addEventListener(Event.ENTER_FRAME, sharkLoop);
}
private function sharkLoop(e:Event):void
{
//test what direction fish is moving in
//If fish is moving right
if (sSharkDirection == "R")
{
//Move Shark right
this.x += nSharkSpeed;
}else
{
//Move Shark left
this.x -= nSharkSpeed;
}
this.y += nSharkSpeed;
}
any help would be appreciated thanks!
It looks like your code does what it means to do: you've told that, firstly, you want sharks to move horizontally, and, secondly, vertically. Well, changing X and Y coordinates gives us diagonal move =)
So, it looks like your code is OK.
Maybe, you should rethink the logic of your application. Also, you may remove/comment the part of code where you change the X position of sharks:
if (sSharkDirection == "R")
{
//Move Shark right
this.x += nSharkSpeed;
}else
{
//Move Shark left
this.x -= nSharkSpeed;
}
And all sharks will move only by Y.
I'm working on a simple game in AS3 where a player should be able to jump on a box.
How to detect if the player landed on the box and didn't run into it?
AS3 to make the player jump:
var grav:Number = 10;
var jumping:Boolean = false;
var jumpPow:Number = 0;
stage.addEventListener(KeyboardEvent.KEY_DOWN, onDown);
stage.addEventListener(Event.ENTER_FRAME, update);
function onDown(evt:KeyboardEvent):void
{
if(evt.keyCode == Keyboard.UP)
{
//umbau das mehrfach tab bis höhe erreicht?
if(jumping != true)
{
jumpPow = -10;
jumping = true;
}
}
}
function update(evt:Event):void
{
if(jumping)
{
player_mc.y += jumpPow;
jumpPow += grav;
if(player_mc.y >= stage.stageHeight)
{
jumping = false;
player_mc.y = stage.stageHeight;
}
}
}
This is how the game layout looks like: (the grey box is moving from right to left, the player's position is fixed)
You should start with a simple rectangle collision function:
/* Test collision between a rectangle and another rectangle. */
/* right() and bottom() return x+width and y+height of the parent rectangle. */
Rectangle.prototype.collideRectangle=function(rectangle_){
if (this.x>rectangle_.right()||this.y>rectangle_.bottom()||this.right()<rectangle_.x||this.bottom()<rectangle_.y){
return false;
}
return true;
}
if you are using the gray rectangle as a platform, you can do a simple test to see if the red rectangle is landing on the gray one by using its current and last position:
/* If true, the two rectangles are definitely colliding. */
if (red_rect.collideRectangle(gray_rect)){
/* Get the last position of the bottom of the red rectangle. */
var old_bottom=red_rect.bottom()-red_rect.velocity.y;
/* If the old bottom was above the gray rectangle on the last frame and is colliding in this frame, you know that the red rectangle is landing on the gray rectangle. */
if (old_bottom<gray_rect.y){
/* Place the red rectangle on top of the gray rectangle. */
red_rect.y=gray_rect.y-red_rect.height;
}
}
This is assuming you move the red rectangle by adding the value of velocity.y to its y position on each frame. Also, I'm using JavaScript, but AS3 and JavaScript aren't so different.
If you want more than a platform, and you want full collision, you should consider the penetration depth of the red rect on the gray rect and separate them on the axis with the smallest penetration depth. There are a lot of resources about this stuff online, and AS3 in particular has a lot of game related tutorials with a focus on do it yourself physics. Some really good collision methods are separation of axes theorem (SAT) and GJK (I'm not going to try spelling the names in GJK).
The objective is for the red circle move horizontally to the left and when completely off stage to reappear on the right side.
Why is it that setting the property X in ball.graphics.drawCircle (300, 300, 50); causes the ball to disappear before it reaches the stage left side?
If I leave x being 0 it behaves as I want
Class.
public function RedBall()
{
ball.graphics.beginFill (0xFF0000);
ball.graphics.drawCircle (300, 300, 50);
ball.graphics.endFill();
}
In my main
function update(e:Event):void {
a.ball.x -= 10;
if (a.ball.x < -a.ball.width) {
a.ball.x = stage.stageWidth + a.ball.width;
}
}
I think this probably must be some very obvious errors as I'm beginning to learn AS3 but if needed I can post the whole code.
You are drawing your circle at a point of 300,300, but you are not later accounting for that in your code where you check its position.
You can do one of two things.
Recommended:
Draw the circle at the point of origin, and place the instance of ball at an x of 300.
Alternative:
Use the ball's actual bounds to determine its position:
function update(e: Event): void {
ball.x -= 10;
if (ball.getBounds(stage).x < -ball.width) {
ball.x = stage.stageWidth - ball.getBounds(stage).x;
}
}
I have two buttons that moves a movieclip up/down the Y-axis. How do I get the movieclip to stop at a certain height, and still be able to move it in the opposite direction?
I need this to work like this:
When you press the down-button, the movieclip goes downwards, but not past Y=500.
When you press the up-button, the movieclip goes upwards, but not past Y= 300.
I get the movieclip to stop at the correct point (500), but when it reaches this point it's stuck..
so it won't go upwards again if I press the up-button.
can someone help me please?:)
here's my code so far:
1) decrease = the down-button
2) increase = up-button
3) stempel = the movieclip I want to stop on the Y-axis
var moveStempel = 0;
decrease.addEventListener(MouseEvent.MOUSE_DOWN, decreasePressed);
decrease.addEventListener(MouseEvent.MOUSE_UP, removeEnterFrame);
increase.addEventListener(MouseEvent.MOUSE_DOWN, increasePressed);
increase.addEventListener(MouseEvent.MOUSE_UP, removeEnterFrame);
function decreasePressed(e:MouseEvent):void
{
moveStempel = 2;
addEnterFrame();
}
function increasePressed(e:MouseEvent):void
{
moveStempel = -2;
addEnterFrame();
}
// ADD ENTER FRAME
function addEnterFrame():void
{
this.addEventListener(Event.ENTER_FRAME, update);
}
function removeEnterFrame(e:MouseEvent):void
{
this.removeEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void
{
if (stempel.y < 500)
{
stempel.y += moveStempel;
trace("inside");
}
else if (stempel.y > 500)
{
stempel.stop();
trace("outside");
}
In your code right now, once stempel has a y value greater than 500, it will never be able to move again.
There are two conditions when stempel can move: if it's moving down, it can't be at the bottom of the allowed area, and if it's moving up, it can't be at the top of the allowed area.
if ((stempel.y < 500 && moveStempel == 2) || (stempel.y > 300 && moveStempel == -2))
{
stempel.y += moveStempel;
trace("inside");
}
else
{
stempel.stop();
trace("outside");
}