Problems with a simple physics system in AS3 - actionscript-3

Well, first of all, I'm a student, so I really beg to you to be patient in the answer. I'm not a english speaker too, by the way.
Everything begins because I'll attend a Game Jam and I already started to write (or trying to write) a simple "physics" code, who I really was thinking would be easy.
I was working with classes and using hitTestObject for colision detection.
Actually I was having issues since the begin, but I was constantly trying to fix it. At this time the code really sucks and I'm already thinking in another way to do it. But something puzzles me.
Here's a part of the the code who I'd already written (It probably seems very newbie). Most part of the code is bullshit, just take a look in the last "else if".
Note: this is the "block" class, and the "obj" it's the Movie Clip of the player.
public function checkObj(obj:MovieClip):void
{
if (this.hitTestObject (obj))
{
if (this.y < obj.y)
{
if (this.x - this.width/2 <= obj.x+obj.width/2 && this.x + this.width/2 >= obj.x-obj.width/2)
{
downCol = true;
}
}
else if (this.y + this.height/2 > obj.y-obj.height/2)
{
if (this.x - this.width/2+2 <= obj.x+obj.width/2 && this.x + this.width/2-2 >= obj.x-obj.width/2)
{
upCol = true;
onBox = true;
}
}
if (this.x - this.width/2 >= obj.x+obj.width/2-2)
{
if (this.y - this.height/2<= obj.y+obj.height/2&& this.y + this.height/2>= obj.y-obj.height/2)
{
leftCol = true;
}
}
else if (this.x + this.width/2 <= obj.x-obj.width/2-2)
{
if (this.y + 5>= obj.y-obj.height/2 && this.y - 5<= obj.y+obj.height/2)
{
trace ("Collided on right");
rightCol = true;
}
}
}
}
For some reason, this way it doesn't work. It never returns me the message.
But if I do a little change:
public function checkObj(obj:MovieClip):void
{
if (this.x + this.width/2 <= obj.x-obj.width/2-2)
{
objOnRight = true;
}
if (this.hitTestObject (obj))
{
//...
else if (objOnRight == true)
{
if (this.y + 5>= obj.y-obj.height/2 && this.y - 5<= obj.y+obj.height/2)
{
rightCol = true;
trace ("Collided on right");
}
}
}
}
It works. Just because I checked the X axis of "obj " before testing the collision. I know this code it's bad at all, but if someone could help me to understand that error and maybe guide me to a more efficient solution I'll really appreciate it! Thank you.

Try this for the last else if
else if (this.x + this.width / 2 <= obj.x + obj.width / 2 - 2) {
if (this.y + 5 >= obj.y - obj.height / 2 && this.y - 5 <= obj.y + obj.height / 2) {
trace("Collided on right");
rightCol = true;
}
}
just change the "-" to "+" .

Ok, forget it. I wrote a brand new code, without hitTest, and it works like a charm. I think the Math.abs solved the problem with negative numbers.
Thanks for your help, kare81.
Here's the code:
public function checkObj(obj:MovieClip,place:int):void
{
if (obj.x + obj.width / 2 > this.x - width / 2 && obj.x < this.x - width / 2 + 7 && Math.abs (obj.y - y) < height / 2)
{
obj.x = this.x - width / 2 - obj.width / 2;
}
if (obj.x - obj.width / 2 < this.x +width / 2 && obj.x > this.x + width / 2 - 7 && Math.abs (obj.y - y) < height / 2)
{
obj.x = this.x +width / 2 + obj.width / 2;
}
if (Math.abs (obj.x- this.x) < width / 2 + obj.width / 2 && obj.y<y-height/2 && obj.onFloor > y-height/2 && obj.onBlock != place)
{
obj.onFloor = y - height / 2;
obj.onBlock = place;
}
if (Math.abs (obj.x - this.x) >= width / 2 + obj.width / 2 && obj.onBlock == place)
{
obj.onFloor = 450;
}
if (obj.y - obj.height / 2 < y + height /2 && obj.y > y && Math.abs (obj.x - this.x) < width / 2 + obj.width / 2)
{
obj.y = y + height / 2 + obj.height / 2;
}
}

Related

AS3 TypeError: Error #1009 Pong game

I know there are alot of posts about this error but im new at AS3 and i can't figure out how to use any of these specific answers to help me.
Im working on a project at school and I keep getting
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at pong_fla::MainTimeline/loop()
I have tried alot of things to try and fix this but it still keeps occuring.
Here is the code with the loop its referring to.
var ballSpeedX: int = -6;
var ballSpeedY: int = -6;
var cpuPaddleSpeed: int = 3;
var playerScore: int = 0;
var cpuScore: int = 0;
var wintotal: int = 1;
init();
function init(): void {
stage.addEventListener(Event.ENTER_FRAME, loop);
}
function calculateBallAngle(paddleY: Number, ballY: Number): Number {
var ySpeed: Number = 5 * ((ballY - paddleY) / 25);
return ySpeed;
}
function updateTextFields(): void {
playerScoreText.text = ("Player Score: " + playerScore);
cpuScoreText.text = ("CPU Score: " + cpuScore);
}
function loop(e: Event): void {
if (playerScore == wintotal) {
gotoAndStop(3);
}
if (cpuScore == wintotal) {
gotoAndStop(4);
}
if (playerPaddle.hitTestObject(ball) == true) {
if (ballSpeedX < 0) {
ballSpeedX *= -1;
ballSpeedY = calculateBallAngle(playerPaddle.y, ball.y);
}
} else if (cpuPaddle.hitTestObject(ball) == true) {
if (ballSpeedX > 0) {
ballSpeedX *= -1;
ballSpeedY = calculateBallAngle(cpuPaddle.y, ball.y);
}
}
if (cpuPaddle.y < ball.y - 10) {
cpuPaddle.y += cpuPaddleSpeed;
} else if (cpuPaddle.y > ball.y + 10) {
cpuPaddle.y -= cpuPaddleSpeed;
}
playerPaddle.y = mouseY;
if (playerPaddle.y - playerPaddle.height / 2 < 0) {
playerPaddle.y = playerPaddle.height / 2;
} else if (playerPaddle.y + playerPaddle.height / 2 > stage.stageHeight) {
playerPaddle.y = stage.stageHeight - playerPaddle.height / 2;
}
ball.x += ballSpeedX;
ball.y += ballSpeedY;
if (ball.x <= ball.width / 2) {
ball.x = ball.width / 2;
ballSpeedX *= -1;
cpuScore++;
updateTextFields();
} else if (ball.x >= stage.stageWidth - ball.width / 2) {
ball.x = stage.stageWidth - ball.width / 2;
ballSpeedX *= -1;
playerScore++;
updateTextFields();
}
if (ball.y <= ball.height / 2) {
ball.y = ball.height / 2;
ballSpeedY *= -1;
} else if (ball.y >= stage.stageHeight - ball.height / 2) {
ball.y = stage.stageHeight - ball.height / 2;
ballSpeedY *= -1;
}
}
I am new to StackOverflow, if i can improve on my question plaese let me know.
Here is the full file:
DropBox Link
it happens because MovieClips don't exist in other frames
removing the listener fixed most of the errors (not all of them, however)
if (playerScore == wintotal) {
//remove the listener when leaving the frame
stage.removeEventListener(Event.ENTER_FRAME, loop);
gotoAndStop(3);
}
if (cpuScore == wintotal) {
//remove the listener when leaving the frame
stage.removeEventListener(Event.ENTER_FRAME, loop);
gotoAndStop(4);
}
//check if MovieClips exist
if(!playerPaddle || !cpuPaddle){
return;
}
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at pong_fla::MainTimeline/loop()
actually this error says what to do. Flash cant find a MC on your stage or MC dont have that property to use ;) Just check your code again and use trace for detect what is cause your error.
This error is thrown when ActionScript can't find an object reference at the current scope. I would double check that both playerPaddle and ball exist on the stage and not inside MovieClips. Remember instance names are case sensitive so Ball wouldn't be the same as ball.

Error #1034: Type Coercion failed: cannot convert objects::Player#a1a4101 to flash.display.MovieClip

I recently started programming games with action script 3 for a school project. Now after watching some tutorials I wanted to combine the script with eachother to get the game I want.
The problem that now occurs is that a movieclip need to be converted, but flash is unable to. Why it has to be converted: I don't have a clue. As I said before, I am an absolute beginner.
I've searched the web and this website as well but nothing seems to be the same so I don't know how to solve it.
Flash Builder gives the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert objects::Player#a1d2101 to flash.display.MovieClip.
at screens::inGame/checkStuff()[C:\Users\Henk-Jan\Dropbox\Project P2 CMD 1\4. Multimedia production\Tutorials\StarlingProject\src\screens\inGame.as:294]
inGame.as Line 294:
for(var i:int = 0; i < blocks.length; i++)
{
blocks[i].checkObj(char, i); //LINE 294*************************
for(var s:int = 0; s < enemies.length; s++)
blocks[i].checkObj(enemies[s], i);
}
checkObj function in Block.as:
public function checkObj(obj:MovieClip, place:int):void{
if(obj.x + obj.width / 2 > x - width / 2 && obj.x < x - width / 2 + 7 && Math.abs(obj.y - y) < height /2){
obj.x = x - width / 2 - obj.width / 2;
}
if(obj.x - obj.width / 2 < x + width / 2 && obj.x > x + width / 2 - 7 && Math.abs(obj.y - y) < height /2){
obj.x = x + width / 2 + obj.width / 2;
}
if(Math.abs(obj.x - x) < width / 2 + obj.width / 2 && obj.y < y - height / 2 && obj.floor > y - height / 2 && obj.onBlock != place){
obj.floor = y - height / 2;
obj.onBlock = place;
}
if(Math.abs(obj.x - x) >= width / 2 + obj.width / 2 && obj.onBlock == place){
obj.onBlock = -1;
obj.floor = 600;
}
if(obj.y - obj.height / 2 < y + height / 2 && obj.y > y && Math.abs(obj.x - x) < width / 2 + obj.width / 2){
obj.y = y + height / 2 + obj.height / 2;
}
so, this is build in a Starling framework. The above code i part of a larger code that I won't post here, as you guys probably won't like that. var blocks is an Array that has the blocks in it where the char stands on ingame.
For the guys who are willing to import the whole code to flash builder > http://www75.zippyshare.com/v/37202056/file.html
I hope my problem can be solved very quickly, as my deadline is next week already...
best regards,
Henk-Jan
The problem isn't that you need to convert a movieclip, the problem is that you're trying to coerce a Player class into a MovieClip class (which it isn't). checkObj() has a first argument of obj:MovieClip. This is the issue. Either change it to obj:Player or generalize it with a wildcard obj:*.

Error with jump function when putting script on movieclip

I'm having a problem with my jump function for a platformer engine. I've moved all of the hit testing onto the individual platforms in the level, so I don't have to write things out for each individual one. The problem with this is that only the first movieclip added to the stage can be jumped on to. The others just make the player sink through the floor if up is held down (as they should- as he's not meant to be there there's nothing to stop him).
So the problem is that the check for the jump just isn't registering properly on the second block. Here's the code (sorry about the excessive MovieClip(parent) s)
var playerRef:MovieClip = MovieClip(parent).player;
stage.addEventListener(Event.ENTER_FRAME, hitUpdate);
function hitUpdate(e:Event):void {
if (playerRef.hitTestPoint(playerRef.x,this.y - (playerRef.height/2)) && playerRef.x + playerRef.width > this.x && playerRef.x < this.x + this.width && !MovieClip(parent).upDown) {
MovieClip(parent).downMomentum = 0;
playerRef.y = this.y - playerRef.height;
}
if (playerRef.hitTestPoint(playerRef.x,this.y + this.height) && playerRef.x + playerRef.width > this.x && playerRef.x < this.x + this.width) {
MovieClip(parent).downMomentum = 0;
playerRef.y = this.y + this.height + MovieClip(parent).gravity;
}
if (playerRef.hitTestPoint(this.x,playerRef.y) && playerRef.y + playerRef.height > this.y && playerRef.y < this.y + this.height) {
MovieClip(parent).speed = 0;
playerRef.x = this.x - playerRef.width;
}
if (playerRef.hitTestPoint(this.x + this.width,playerRef.y) && playerRef.y + playerRef.height > this.y && playerRef.y < this.y + this.height) {
MovieClip(parent).speed = 0;
playerRef.x = this.x + this.width;
}
if (playerRef.hitTestObject(this)) {
MovieClip(parent).groundTouch = true;
} else {
MovieClip(parent).groundTouch = false;
}
}
And the jump function runs like this:
stage.addEventListener(Event.ENTER_FRAME, updates);
function updates(e:Event):void{
player.y += downMomentum;
if(!groundTouch && downMomentum < downMomCap){
downMomentum += gravity;
}
if(downMomentum > downMomCap){
downMomentum = downMomCap;
}
if(upDown && !jumping && groundTouch){
jumping = true;
jumpTimer.reset();
jumpTimer.start();
}
}
jumpTimer.addEventListener(TimerEvent.TIMER, jumpTick);
function jumpTick(e:TimerEvent):void{
if(downMomentum*-1 < downMomCap){
downMomentum -= jumpProg * jumpIncrement;
}else{
downMomentum = downMomCap * -1;
}
jumpProg -= 1;
}
jumpTimer.addEventListener(TimerEvent.TIMER_COMPLETE, jumpDone);
function jumpDone(e:TimerEvent):void{
jumpTimer.stop();
jumping = false;
jumpProg = 5;
}
I just can't find a solution to this, though I suspect it's something to do with how it checks for the player touching the platform.

Breakout hitbox system

I've been working on this for several weeks now and I can get it to work as It to work. It's almost there I guess there is just something I'm missing. I basically cant get the collision detection betwen the blocks and the ball to work like I wnat them to work.
Dump SWF
The ball still has a chance to plow loads of block within seconds. I would love to hear form people who have had a similiar problem.
Here's the code;
private function checkCollision():void
{
grdx = Math.floor((ball.x) / 28);
grdy = Math.floor((ball.y) / 14);
ngrdx = Math.floor((ball.x + dx) / 28);
ngrdy = Math.floor((ball.y + dy) / 14);
if (grdy <= level.length - 1 && ngrdy <= level.length - 1 && grdy >= 0 && ngrdy >= 0)
{
if(level[grdy][ngrdx] > 0)
{
level[grdy][ngrdx] = 0;
bnm = "Block_" + grdy + "_" + ngrdx;
if (this.getChildByName(bnm) != null)
{
this.removeChild(this.getChildByName(bnm));
dx *= -1;
totalBreaks++;
trace("Hit on X");
trace("Block: " + totalBreaks + " / " + totalBlocks);
}
}
else if(level[ngrdy][grdx] > 0)
{
bnm = "Block_" + ngrdy + "_" + grdx;
level[ngrdy][grdx] = 0;
if (this.getChildByName(bnm) != null)
{
this.removeChild(this.getChildByName(bnm));
dy *= -1;
totalBreaks++;
trace("Hit on Y");
trace("Block: " + totalBreaks + " / " + totalBlocks);
}
}
if(level[ngrdy][ngrdx] > 0)
{
bnm = "Block_" + ngrdy + "_" + ngrdx;
level[ngrdy][ngrdx] = 0;
if (this.getChildByName(bnm) != null)
{
this.removeChild(this.getChildByName(bnm));
dy *= -1;
dx *= -1;
totalBreaks++;
trace("hit on X,Y");
trace("Block: " + totalBreaks + " / " + totalBlocks);
}
}
}
}
I'm not sure I got this right but I think one problem can be with your if else if statements.
From your example, a call to checkCollision() might change twice your dx and dy vars, resulting in the ball keep going in the same direction while it hit a brick.
If I'm right then you may refactor your if statements like the following:
if (level[ngrdy][ngrdx] > 0)
{
[...]
}
else if (level[grdy][ngrdx] > 0)
{
[...]
}
else if (level[ngrdy][grdx] > 0)
{
[...]
}
Besides, it's a good practice to enclose simple tests into parenthesis. So instead of writing that:
if (grdy <= level.length - 1 && ngrdy <= level.length - 1 && grdy >= 0 && ngrdy >= 0)
I would write this :
if ((grdy <= level.length - 1) && (ngrdy <= level.length - 1) && (grdy >= 0) && (ngrdy >= 0))
thus making the code more readable.
Good work though, keep going on!
EDIT:
As your comment suggest it is not a correct answer, I dig a bit more and I now have another suggestion, using some booleans to check whether the direction should be flipped on both axes. I also did a bit of refactoring:
private function checkCollision():void
{
grdx = Math.floor((ball.x) / 28);
grdy = Math.floor((ball.y) / 14);
ngrdx = Math.floor((ball.x + dx) / 28);
ngrdy = Math.floor((ball.y + dy) / 14);
var flipX:Boolean = false;
var flipY:Boolean = false;
if ((grdy <= level.length - 1) && (ngrdy <= level.length - 1) && (grdy >= 0 && ngrdy >= 0))
{
if (testBlock(grdx, ngrdy))
{
flipY = true;
}
if (testBlock(ngrdx, grdy))
{
flipX = true;
}
if (testBlock(ngrdx, ngrdy))
{
flipX = true;
flipY = true;
}
dx *= flipX ? -1 : 1;
dy *= flipY ? -1 : 1;
}
}
private function testBlock(xPos:int, yPos:int):Boolean
{
if (level[yPos][xPos] > 0)
{
trace("hit on X,Y");
level[yPos][xPos] = 0;
breakBlock("Block_" + yPos + "_" + xPos);
trace("Block: " + totalBreaks + " / " + totalBlocks);
return true;
}
return false;
}
private function breakBlock(blockName:String):void
{
if (this.getChildByName(blockName))
{
this.removeChild(this.getChildByName(blockName));
totalBreaks++;
}
}
If it happened to be the correct solution, I'd clean this answer...

ActionScript 3.0 Slider doesn't continue when sliding to start

I made a slider to search trough my actionscript video.
Maybe you'll understand better if you can see what i'm working on:
http://www.stevevo.sin.khk.be/Website%202SDesign/ -> this is the link of the testserver where the website i'm building is running on. You'll see the huge banner in the center, rollover it an you'll see a slider and a pause/start button.
The slider works great exept for 1 little thing. When you drag the slider to the utter left actionScript 3.0 will start the movie again (i asume), now drag to the right without interuptions and the slider won't move to the right as he should (all in one drag).
Why ain't it possible to first slide to the start and then continue sliding?
MY CODE:
very simple. You start dragging, the rectangle is the dragRestriction. The Movie stops. isDragging = true.
SearchBarSlider.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
function fl_ClickToDrag(event:MouseEvent):void
{
var rect:Rectangle = new Rectangle(SearchBar.x + 3,
SearchBar.y,
SearchBar.width - 10,
0);
SearchBarSlider.startDrag(false, rect);
stop();
isDraging = true;
}
Again easy peasy. Drag stops. Movie starts to play again. isdragging = false;
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
function fl_ReleaseToDrop(event:MouseEvent):void
{
SearchBarSlider.stopDrag();
play();
isDraging = false;
}
When the mouse moves when dragging the x-position of the slider will be converted to the right amount of frames. In between the 3 parts other lengths aply.
stage.addEventListener(MouseEvent.MOUSE_MOVE, fl_Drag);
function fl_Drag(event:MouseEvent):void
{
if(isDraging == true) {
if(SearchBarSlider.x - (SearchBar.x + 3) < 20){
gotoAndStop(Math.round(((SearchBarSlider.x - (SearchBar.x + 3)) / 20) * 320));
} else if(SearchBarSlider.x - SearchBar.x + 3 >= 20 && SearchBarSlider.x - SearchBar.x + 3 < 40){
gotoAndStop(Math.round(((SearchBarSlider.x - (SearchBar.x + 3) - 20) / 20) * 365) + 365);
} else {
gotoAndStop(Math.round(((SearchBarSlider.x - (SearchBar.x + 3) - 40) / 20) * 465) + 685);
}
}
}
This event accurs at every frame when not dragging. But instead of converting the x-position of the slider to frames this will convert frames to x-positon of the slider.
stage.addEventListener(Event.ENTER_FRAME, fl_frameEvent);
function fl_frameEvent(e:Event):void
{
if(isDraging == false) {
if(currentFrame < 365){
SearchBarSlider.x = SearchBar.x + 3 + Math.round((currentFrame / 365) * 20);
} else if(currentFrame >= 365 && currentFrame < 685){
SearchBarSlider.x = SearchBar.x + 23 + Math.round(((currentFrame - 365) / 320) * 20);
} else {
SearchBarSlider.x = SearchBar.x + 43 + Math.round(((currentFrame - 685) / 465) * 20);
}
}
}
Does the second function really not occur when dragging? Do you remove it, or is it running at the same time? I think your enter_frame function and your mouse_move function are fighting each other. in your drag function add this:
stage.removeEventListener(Event.ENTER_FRAME, fl_frameEvent);
and in your drop function add this:
stage.addEventListener(Event.ENTER_FRAME, fl_frameEvent);
Another workaround, I noticed if you zoom way way in on the slider, if you come 99.9% of the way left, but don't quite line it up, it works as expected, so you could just adjust your draggable rectangle to leave just a tiny space on the left side.
SearchBar.x + 4
I actually fixed my own problem here's the solution.
stage.addEventListener(MouseEvent.MOUSE_MOVE, fl_Drag);
function fl_Drag(event:MouseEvent):void
{
if(isDraging == true) {
if(SearchBarSlider.x - (SearchBar.x + 3) < 1){
} else if(SearchBarSlider.x - (SearchBar.x + 3) < 20){
gotoAndStop(Math.round(((SearchBarSlider.x - (SearchBar.x + 3)) / 20) * 320));
} else if(SearchBarSlider.x - SearchBar.x + 3 >= 20 && SearchBarSlider.x - SearchBar.x + 3 < 40){
gotoAndStop(Math.round(((SearchBarSlider.x - (SearchBar.x + 3) - 20) / 20) * 365) + 365);
} else {
gotoAndStop(Math.round(((SearchBarSlider.x - (SearchBar.x + 3) - 40) / 20) * 465) + 685);
}
}
}
The problem was that when the gotoAndStop event accured at frame 1 the whole program restarted because at frame 1 the actions layer reinitiates the code. So the drag that was busy got ended. With the new piece of code the searchbar won't execute gotoAndStop(1);