How to check if mouse is on a shpae in Flash - actionscript-3

I am building a simple flash game in AS3 and I was wondering if I could use code similar to "hitTestPoint()" except it applies to a shape and not a symbol?
The maze is simply a line shape, so if the ball moves off the shape then the game is terminated. Is this possible?
Thanks,
Peter

Simple enough. Just test if the maze is found at the current location of the ball.
function test():Boolean {
// First we get the absolute coordinates of the ball
var loc:Point = ball.localToGlobal(new Point(0,0));
// Next we collect all the DisplayObjects at that coordinate.
var stack:Array = getObjectsUnderPoint(loc);
var found:Boolean = false;
// Now we cycle through the array looking for our maze
for each (var item in stack) {
if (item.name == "mazeShape") {
found = true;
}
}
return found;
}
If you're really interested in whether the mouse (and not the ball) is off the maze, just replace the first line with this:
var loc:Point = new Point(mouseX, mouseY);

Depending how your game looks, you could also use coordinates for this.
Just tell the game if Player > 100 Y it is off the game it's limits = Restart.
It might won't be the most solid solution but it is definetely a way to solve it as I don't believe there is a function for it, please do correct me if I am wrong.

The AS3 Collision Detection Kit will let you detect hits based on color if separating the maze into smaller symbols is not appropriate.

Related

Drawing a path of points html canvas

I made a double pendulum with canvas.
Here is the result: https://jsfiddle.net/zndo9vh4/
As you guys can see a trace is drawn everytime the second part of the pendulum moves, and my way of doing that is by appending each coordinate to a "trace" array.
var trace = []
trace.push([x2,y2]);
And then I draw the trace by joining each coordinate with the last one:
for (let i = 1; i < trace.length; i++) {
c.moveTo(trace[i][0], trace[i][1])
c.lineTo(trace[i-1][0], trace[i-1][1])
}
I want to improve it. What i've tried so far is only adding coordinates that aren't already in the array, but it's not a big improvent because the lines are drawn every loop
var trace = []
if(trace.includes([x2, y2]) != true){
trace.push([x2,y2]);
}
The way I think could be a good improvement is by having 2 canvas (I don't know if its possible) and then draw each point but only in that canvas so I doesnt have to be redrawn. But I dont know how to implement that.
Thanks in advice
Your improvement idea is great. You can indeed have two canvases!
There are two ways to go about it.
Offscreen canvas
Using what's called an offscreen canvas (a canvas that is created in JavaScript but not added to the DOM), you can draw all the points onto it and then using drawImage (which can accept a canvas element) pass the canvas to the main context.
var offscreenCanvas = document.createElement('canvas');
var offscreenC = offscreenCanvas.getContext('2d');
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
// in animate function, draw points onto the offscreen canvas instead
// of the regular canvas as they are added
if(trace.includes([x2, y2]) != true){
trace.push([x2,y2]);
var i = trace.length-1;
if (i > 1) {
offscreenC.strokeStyle = 'white'
offscreenC.beginPath();
offscreenC.moveTo(trace[i][0], trace[i][1])
offscreenC.lineTo(trace[i-1][0], trace[i-1][1])
offscreenC.stroke();
}
}
c.drawImage(offscreenCanvas, 0, 0);
Layered Canvases
One of the downsides to the offscreen canvas approach is that you have to draw it to the main canvas every frame. You can further improve the approach by layering two canvases on top of one another, where the top one is just the pendulum and the bottom one the trace.
This way, you never have to redraw the offscreen canvas onto the main canvas, and save yourself some rendering time.
Updated jsfiddle

AS3 tween object not working with .hitTestObject()

I am having a major problem in my new browser app.
Okay so I made game where different cubes (squares) spawn at the top of the screen and I use the Tween class to make them go down the screen and then disappear.
However I want to detect a collision when a cube hits the player (that is also a flying cube).
I tried everything, truly everything but it does not seem to work. The problematic thing is that when I remove the "Tween" function it does detect collision with the hitTestObject method but when I add the "Tween" line collision won't be detected anymore.
It looks like this:
function enemiesTimer (e:TimerEvent):void
{
newEnemy = new Enemy1();
layer2.addChild(newEnemy);
newEnemy.x = Math.random() * 700;
newEnemy.y = 10;
if (enemiesThere == 0)
{
enemiesThere = true;
player.addEventListener(Event.ENTER_FRAME, collisionDetection)
}
var Tween1:Tween = new Tween(newEnemy, "y", null, newEnemy.y, newEnemy.y+distance, movingTime, true);
}
And the collision detection part:
private function collisionDetection (e:Event):void
{
if (player.hitTestObject(newEnemy))
{
trace("aaa");
}
}
I am desperate for some information/help on the topic, it's been bugging me for days.
Thanks for your time, I would be very happy if someone could help me out^^
First, make sure the "newEnemy" instance and the "player" instance are within the same container. If they are not, their coordinate systems might not match up and could be the source of your problem.
Otherwise, you need to keep a reference to each enemy instance you create. It looks like you are only checking against a single "newEnemy" variable which is being overwritten every time you create a new enemy. This might be why you can successfully detect collision between the player and the most recent "enemy" instance.
So... you need a list of the enemies, you can use an Array for that.
private var enemyList:Array = [];
Every time you create an enemy, push it to the Array.
enemyList.push(newEnemy);
In your "collisionDetection" function, you need to loop through all of the enemies and check if the player is touching any of them.
for(var i:int = 0; i < enemyList.length; i++)
{
var enemy = enemies[i];
if (player.hitTestObject(enemy))
{
trace("Collision Detected!");
enemy.parent.removeChild(enemy); // remove the enemy from the stage
enemies.splice(i, 1); // remove the enemy from the list
}
}
I'd suggest that you move to TweenMax, it just might solve your problem, and in my experience it's much better in every possible way.
Scroll down the following page to see a few variations of this library, I myself use TweenNano, they're completely free of charge:
https://greensock.com/gsap-as
I think some plugins cost money, but I doubt you'll ever need them.

Detect collision between Actors

I'm trying to implement a collision detector between my Player (Actor) and my Obstacle (Actor too), and I wonder what's the best way to perform a collision detection between them. I see some users saying that they create a Rectangle object in the class and update its bounds every frame, but I don't know if this is the best way to perform this (I'm also trying to make this, but my collision detector method triggers before my Player touches the Obstacle).
This is what I'm trying to check:
public boolean touchedWall() {
// Loop for the obstacles
for (Obstacle obstacle : this.world.getObstacles()) {
// Check if player collided with the wall
if (this.bounds.overlaps(obstacle.getBounds())) {
Gdx.app.log(Configuration.TAG, "collided with " + obstacle.getName());
return true;
}
}
return false;
}
And this is where the method triggers (it should trigger when the Player bounds hit the wall):
I figured out! Instead of using this.bounds.set(x, y, width, height), I was using this.bounds.set(x, y, height, width) like this:
this.bounds.set(this.getX(), this.getY(), this.getHeight(), this.getWidth());
Sorry for my mistake.

Canvas Animation Not Rendering

I'm new to the canvas tag and am playing around with some animation. Basically, I'm trying to setup a "ground" section composed of multiple images (similar to an 8bit side scroller game like Mario Brothers). The ground will be composed of multiple images, which I've built a constructor function to load these and tile them across the bottom.
function Ground(context,ImageName,ImgX,ImgY,ImgW,ImgH){
this.width=ImgW;
this.height=ImgH;
this.x=ImgX;
this.y=ImgY;
img=new Image();
img.onload=function(){context.drawImage(img,ImgX,ImgY,ImgW,ImgH);};
img.src='images/'+ImageName;};
This seems to work out just fine. I've then setup the rest of the animation, including a basic setup for Key Left/Right events, like so:
window.onload=function(){
var canvas=document.getElementById('canvas'),
context=canvas.getContext('2d'),
Grounds=[],
ImgX=-150; // INITIAL STARTING X FOR FIRST GROUND TILE
// INSERT GROUND ELEMENTS
for(var i=0,l=8; i<l; i++){
var ImgX+=150;
Grounds[i]=new Ground(context,"ground.png",ImgX,650,150,150);
};
// ASSIGN LEFT/RIGHT KEYS
window.addEventListener('keyup',function(event){
switch(event.keyCode){
case 37:
for(var i=0,l=Grounds.length; i<l; i++){
Grounds[i].x+=10;
};
break;
case 39:break;
};
});
// ANIMATION LOOP
(function drawFrame(){
window.mozRequestAnimationFrame(drawFrame,canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
}());
};
I know exactly what my problem is, but don't know how to solve it. The animation loop is clearing the canvas every frame, but not redrawing the updated position (if any) when the user presses the left arrow key.
I'm missing the redraw part here and I'm not exactly sure how to handle this or if I'm approaching this entirely wrong. Any help is very appreciated! Thanks!
First of all you're incrementing the property x of the ground tiles but that property is not even used anywhere in your code. Modify your code so that the onload event of those image objects draws the image according to their own x property so changes to it will actually affect what is drawn. Also add the image object as a property of the Ground object so you can access it later on from outside.
Your approach is really not so good but if you want to do it without going back to 0 do it as follows:
function Ground(context,ImageName,ImgX,ImgY,ImgW,ImgH){
this.width=ImgW;
this.height=ImgH;
this.x=ImgX;
this.y=ImgY;
var self = this; // Add local reference to this Ground instance
this.img=new Image(); // img is now a property too
this.img.onload=function(){context.drawImage(this, self.x, self.y,self.width,self.height);};
this.img.src='images/'+ImageName;};
Ok so now you can change the property x of the ground tiles and call the draw function of it again (which is the onload event).
Grounds[i].x+=10;
Grounds[i].img.dispatchEvent(new Event("load"));
Please note that you should really make the updates of all the values first and then all the draw calls separately.
Can you not just add a draw method? You usually so something like this:
init -> update -> clear, redraw -> update -> clear, redraw -> ...
// ANIMATION LOOP
(function drawFrame(){
window.mozRequestAnimationFrame(drawFrame,canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
contect.drawImage(...);
}());

Use bitmapData.hitTest on two bitmapData with centered registration point

I've spent all the day on this, it's time to ask for your help :)
I'm trying to do collision detection of two display objects, both have centered registration point.
On my stage I have fixed elements that when added to stage are pushed in an Array called "zoneUsed". All the displayObject in my project have the registration point in the center.
My goal is to click on the stage, and check if in the clicking coords I could create a circle. My plan was to create a Sprite for the new object, cycle on the zoneUsed array, and check if the new sprite have enough space to live.
Here my code so far:
private function checkSpaceForNewMarker (markerToCheck:Sprite):Boolean {
var isPossible:Boolean = true;
var bmdataToCheck:BitmapData = new BitmapData (markerToCheck.width, markerToCheck.height, true, 0);
var m:Matrix = new Matrix ();
m.tx = markerToCheck.width/2;
m.ty = markerToCheck.height/2;
bmdataToCheck.draw (markerToCheck, m);
for (var i:int = 0; i<zoneUsed.length; i++) {
trace ("*** CHECKING ****");
var bmddataOnTheTable:BitmapData = new BitmapData (zoneUsed[i].width, zoneUsed[i].height, true, 0);
var tableMatrix:Matrix = new Matrix ();
tableMatrix.tx = zoneUsed[i].width/2;
tableMatrix.ty = zoneUsed[i].height/2;
bmddataOnTheTable.draw(zoneUsed[i], tableMatrix);
if (bmdataToCheck.hitTest(new Point(markerToCheck.x, markerToCheck.y), 255, bmddataOnTheTable, new Point (zoneUsed[i].x, zoneUsed[i].y), 255)) {
trace ("COLLISION");
isPossible = false;
} else {
trace ("NO COLLISION");
isPossible = true;
}
}
return isPossible;
}
....But right now the results are weird. Depending on the zones, my traces work or not. What am I doing wrong?
The problem is , you are drawing 1/4 (quarter) part of every object.
BitmapData is not like a Shape, Sprite, MovieClip, and it crops all the pixels, when the drawing bounds is out of the bounds of (0,0,bitmapdata.width, bitmapdata.height) rectangle.
Just remove this lines:
m.tx = markerToCheck.width/2;
m.ty = markerToCheck.height/2;
and also
tableMatrix.tx = zoneUsed[i].width/2;
tableMatrix.ty = zoneUsed[i].height/2;
You don't need this translations.
Also your code may be cause for memory leak. You are creating bitmapdata, but do not dispose it. The garbage collector will not release the memory you have allocated.You must release memory explicitly. Call bitmapdata.dispose() every time you have no need of that bitmapdata.
I'm not sure that the origin of the bitmap has anything to do with the test itself. The very nature of the test would seem to imply that the hittest is based on the RGBA value of the two supplied bitmaps. Anyway rather than picking apart your own implementation I'll just refer you to a tutorial by Mike Chambers (adobe platform evangelist). http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/
Also for more flash tutorials check out www.gotoandlearn.com.