I have the following code in Box2D, I want to move my dynamic body to the point where the mouse is click. Also in the future i want to be able to remove the dynamic body, I am not able to find anything equivalent to world.DeleteBody(...). Please Help.
var world;
var b2Vec2 = Box2D.Common.Math.b2Vec2
, b2BodyDef = Box2D.Dynamics.b2BodyDef
, b2Body = Box2D.Dynamics.b2Body
, b2FixtureDef = Box2D.Dynamics.b2FixtureDef
, b2Fixture = Box2D.Dynamics.b2Fixture
, b2World = Box2D.Dynamics.b2World
, b2MassData = Box2D.Collision.Shapes.b2MassData
, b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
, b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
, b2DebugDraw = Box2D.Dynamics.b2DebugDraw
;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var mouseX, mouseY, isMouseDown;
var bBallBody, bBallbodyDef;
function init() {
world = new b2World(
new b2Vec2(0, 10) //gravity
, true //allow sleep
);
setupWorld() ;
//setup debug draw
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
debugDraw.SetDrawScale(1.0);
debugDraw.SetFillAlpha(0.3);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
window.setInterval(update, 1000 / 60);
};
function setupWorld() {
setupGround();
addBouncingBall();
}
function setupGround() {
var fixDef = new b2FixtureDef;
fixDef.density = 1.0;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
var bodyDef = new b2BodyDef;
//create ground
bodyDef.type = b2Body.b2_staticBody;
bodyDef.position.x = 300;
bodyDef.position.y = 400;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(290, 10);
world.CreateBody(bodyDef).CreateFixture(fixDef);
}
function addBouncingBall() {
var fixDef = new b2FixtureDef;
fixDef.density = 1.0;
fixDef.friction = 1.0;
fixDef.restitution = 0.1;
var bBallbodyDef = new b2BodyDef;
bBallbodyDef.type = b2Body.b2_dynamicBody;
fixDef.shape = new b2CircleShape(Math.random() + 30);
bBallbodyDef.position.x = Math.random() * 300;
bBallbodyDef.position.y = Math.random() * 300;
bBallBody = world.CreateBody(bBallbodyDef).CreateFixture(fixDef);
console.log(bBallBody.m_body.GetPosition().x);
};
document.addEventListener("mousedown", handleMouseMove, true);
function handleMouseMove(e) {
isMouseDown = true;
mouseX = e.clientX;
mouseY = e.clientY;
};
function update() {
if(isMouseDown)
{
for (b = world.GetBodyList() ; b; b = b.GetNext()) {
if (b.GetType() == b2Body.b2_dynamicBody) {
console.log(b.x, b.y);
b.x = 100;
b.y = 100;
}
}
isMouseDown = false;
}
world.Step(1 / 60, 10, 10);
world.DrawDebugData();
world.ClearForces();
};
Update:
Deletion of an object from the world is done as follows,
Create a Timer to Schdule the deletion of the object.
window.setInterval(removeObjScheduledForRemoval, 1000/90);
Collect the objects to be deleted in a Array.
var bricksScheduledForRemoval = Array();
var index = -1;
function removeObjScheduledForRemoval()
{
for(var i = 0; i <= index; i++){
world.DestroyBody(bricksScheduledForRemoval[i]);
bricksScheduledForRemoval[i] = null;
}
bricksScheduledForRemoval = Array();
index = -1;
}
The complete code is available here,
http://box2dinabox.blogspot.in/2012/07/the-completed-bananamonkey-game.html
The documentation for box2dweb is nowhere near as comprehensive as it is for the original C version, so consider searching for "box2d" instead of "box2dweb". Also, looking into the source and searching for the spelling of certain methods could be helpful. Or just look into the box2d flash documentation. Basically, box2dweb has the methods DestroyJoint and DestroyBody.
For more considerations, this could be helpful: http://www.iforce2d.net/b2dtut/removing-bodies
You can remove the body or change the static body to dynamic as this game example does.
http://pixsansar.com/box2dweb-jumping-and-puzzle-ball-level4
Box2dweb has removebody or changeBodyType option, see the source code of it.
Related
I'm creating a audio player with visualizer.
But currently when I press the input to start the audio player my debug console returns:
Uncaught (in promise) DOMException: Failed to load because no
supported source was found.
What I'm currently doing is setting the whole audio element up in JS / jQuery:
var bins = 512;
var backgroundColour = "#2C2E3B";
var barColour = "#EC1A55";
var floorLevel = 32;
var audioContext;
var audioBuffer;
var audioAnalyserNode;
var initialized = false;
var songText = "";
var textSize;
var freqLookup = [];
var canvasContext;
var isStream = true;
var canvasWidth;
var canvasHeight;
var src;
var audioElement;
var isPlaying = false;
var volume = 1;
function play() {
audioElement = document.createElement('audio');
// Opus support check stuff
var streamEndpoint = 'http://**.**.**.**:8003/stream';
var canPlayOpus = (typeof audioElement.canPlayType === "function" && audioElement.canPlayType('audio/ogg; codecs="opus"') !== "");
if(volume > 1) {
volume = volume / 100;
}
audioElement.src = streamEndpoint;
audioElement.crossOrigin = 'anonymous';
audioElement.volume = volume;
audioElement.play();
isPlaying = true;
setUpCanvas(audioElement);
}
function pause() {
audioElement.pause();
audioElement.currentTime = 0;
audioElement.src = '';
isPlaying = false;
}
function setUpCanvas(audioElement){
try {
initCanvas(document.getElementById("canvas"));
if(typeof audioContext === 'undefined') {
audioContext = new AudioContext();
}
if (audioElement) {
isStream = true;
setupAudioApi(true, audioElement);
}
} catch(e) {
console.log(e);
}
}
function setupAudioApi(isStream, audioElement) {
//var src;
if (isStream){
if(typeof src === 'undefined'){
src = audioContext.createMediaElementSource(audioElement);
audioContext.crossOrigin = "anonymous";
audioAnalyserNode = audioContext.createAnalyser();
audioAnalyserNode.fftSize = bins * 4;
src.connect(audioAnalyserNode);
audioAnalyserNode.connect(audioContext.destination);
}
}
if (!isStream) {
src.start();
}
initialized = true;
initFreqLookupTable();
}
function initCanvas(canvasElement) {
canvasContext = canvasElement.getContext('2d');
canvasElement.width = canvasElement.clientWidth;
canvasElement.height = canvasElement.clientHeight;
canvasWidth = canvasElement.width;
canvasHeight = canvasElement.height;
requestAnimationFrame(paint);
}
function getFreqPoint(start, stop, n, binCount) {
return start * Math.pow(stop / start, n / (binCount - 1));
}
function initFreqLookupTable() {
var lastPoint = 0;
var bins = audioAnalyserNode.frequencyBinCount;
for(var i = 0; i < bins / 2; i++) {
//Scale to perceived frequency distribution
var newFreq = getFreqPoint(20, 20000, i * 2, bins);
var point = Math.floor(bins * newFreq / 20000);
while (point <= lastPoint) {
point++;
}
lastPoint = point;
freqLookup.push(point);
}
}
//Render some fancy bars
function paint() {
requestAnimationFrame(paint);
if(!initialized) {
alert('Er is iets fout gegaan');
return false;
}
canvasContext.clearRect(0, 0, canvasWidth, canvasHeight);
canvasContext.fillStyle = backgroundColour;
canvasContext.fillRect(0, 0, canvasWidth, canvasHeight);
var bins = audioAnalyserNode.frequencyBinCount;
var data = new Uint8Array(bins);
audioAnalyserNode.getByteFrequencyData(data);
canvasContext.fillStyle = barColour;
for(var i = 0; i < bins; i++) {
var point = freqLookup[i];
//Pretty much any volume will push it over 128 so we set that as the bottom threshold
//I suspect I should be doing a logarithmic space for the volume as well
var height = Math.max(0, (data[point] - floorLevel));
//Scale to the height of the bar
//Since we change the base level in the previous operations, 256 should be changed to 160 (i think) if we want it to go all the way to the top
height = (height / (256 - floorLevel)) * canvasHeight * 0.8;
var width = Math.ceil(canvasWidth / ((bins / 2) - 1));
canvasContext.fillRect(i * width, canvasHeight - height, width, height);
}
}
The stream is in audio/mpeg format, it does load when I simply create an audio element in HTML with a src.
Can someone help me clarify and find the solution to the DOMException I'm getting. I have been searching other cases of this error but the fixes there didn't resolve the problem.
Try creating the audio tag like this:
var audio = new Audio('audio_file.mp3');
And try setting the type:
audio.type = "audio/mpeg";
I think that will fix your problem.
This creates an element, identical to the one you use in your code.
I suggest you put an extension on your stream.
I know this way works, and I don't know why the other way doesn't.
Spent 6 hours today building this from a tutorial modifying it for my elements, I've been trying for hours to get it to work and i Just can't :/
Here is a link to the tutorial i was following :
http://gamedevelopment.tutsplus.com/tutorials/create-a-simple-space-shooter-game-in-html5-with-easeljs--active-10944
Zip of all the files including the gifs etc. :
http://www.filedropper.com/shooter_1
Raw Javascript Code:
/* Variable Declarations */
var Lives = new Container(); //stores the lives gfx
var Bullets = new Container(); //stores the bullets gfx
var Enemies = new Container(); //stores the enemies gfx
var Boss_Health = 20;
var Score;
var Gfx_Loaded = 0; //used as a preloader, counts the already loaded items
var Center_X = 960;
var Center_Y = 540;
var Ticker_Listener = new Object(); //used as a Ticker listener
var Timer_Source; //references a setInterval method
/* Define Canvas*/
var canvas;
var stage;
/* Background */
var BG_Img = new Image();
var BG;
var BG2_Img = new Image();
var BG2;
/* Characters */
var Player1_Img = new Image();
var Player1;
/* Enemies */
var Enemy1_Img = new Image();
/* Boss */
var Boss1_Img = new Image();
var Boss1;
/* Lives */
var Life_Img = new Image();
/* Bullets */
var Bullet_Img1 = new Image();
/* Alerts */
var Win_Img = new Image ();
var Lose_Img = new Image ();
var Win;
var Lose;
/*Initiation Function*/
function Main () {
canvas = document.getElementbyId('Shooter');
stage = new stage(canvas);
stage.mouseEventsEnabled = true;
/*Sounds*/
SoundJS.addBatch([
{name:'Boss', src:'Boss.mp3', instances:1},
{name:'Shuriken_Hit', src:'Shuriken_Hit.mp3', instances:10},
{name:'Kunai_Throw', src:'Kunai_Throw.mp3', instances:10}]);
/* Load GFX */
BG_Img.src = 'BG_Img.jpg';
BG_Img.name = 'BG';
BG_Img.onload = loadGfx;
BG2_Img.src = 'BG2_Img.jpg';
BG2_Img.name = 'BG2';
BG2_Img.onload = loadGfx;
Player1_Img.src = 'Naruto_Idle.gif';
Player1_Img.name = 'Player1';
Player1_Img.onload = loadGfx;
Enemy1_Img.src = 'Basic_Enemy.gif';
Enemy1_Img.name = 'Enemy1';
Enemy1_Img.onload = loadGfx;
Boss1_Img.src = 'Akatsuki_Boss.gif';
Boss1_Img.name = 'Boss1';
Boss1_Img.onload = loadGfx;
Life_Img.src = 'Life.gif';
Life_Img.name = 'Life';
Life_Img.onload = loadGfx;
Bullet_Img1.src = 'Rasengan_Mid_Air.gif';
Bullet_Img1.name = 'Bullet';
Bullet_Img1.onload = loadGfx;
Win_Img.src = 'Game_Win.gif';
Win_Img.name = 'Game_Win';
Win_Img.onload = loadGfx;
Lose_Img.src = 'Game_Over.gif';
Lose_Img.name = 'Game_Over';
Lose_Img.onload = loadGfx;
/* Ticker */
Ticker.setFPS(30);
Ticker.addListener(stage);
}
/*Preload Function */
function loadGfx(e)
{
if(e.target.name = 'BG'){BG = new Bitmap(BG_Img);}
if(e.target.name = 'BG2'){BG2 = new Bitmap(BG2_Img);}
if(e.target.name = 'Player1'){Player1 = new Bitmap(Player1_Img);}
gfxLoaded++;
if(gfxLoaded == 9)
{
addGameView();
}
}
/* Game View Function */
function addGameView()
{
Player1.x = Center_X - 18.5;
Player1.y = 480 + 34;
/* Add Lives */
for(var i = 0; i < 3; i++)
{
var l = new Bitmap(Life_Img);
l.x = 248 + (25 * i);
l.y = 463;
Lives.addChild(l);
stage.update();
}
/* Score Text */
Score = new Text('0', 'bold 14px Courier New', '#FFFFFF');
Score.maxWidth = 1000; //fix for Chrome 17
Score.x = 2;
Score.y = 476;
/* Second Background */
BG2.y = -480;
/* Add gfx to stage and Tween Ship */
stage.addChild(BG, BG2, Player1, Enemies, Bullets, Lives, Score);
Tween.get(Player1).to({y:425}, 1000).call(Start_Game);
}
/*Move the Player*/
function Move_Player1(e)
{
Player1.x = e.stageX - 18.5;
}
/* Shooting */
function Shoot()
{
var b = new Bitmap(Bullet_Img1);
b.x = Player1.x + 13;
b.y = Player1.y - 20;
Bullets.addChild(b);
stage.update();
SoundJS.play('Kunai_Throw');
}
/* Adding Enemies */
function Add_Enemy ()
{
var e = new Bitmap(Enemy1_Img);
e.x = Math.floor(Math.random() * (320-50))
e.y = -50
Enemies.addChild(e);
stage.update();
}
function Start_Game()
{
stage.onMouseMove = Move_Player1;
BG.onPress = Shoot;
BG2.onPress = Shoot;
Ticker.addListener(Ticker_Listener, false);
Ticker_Listener.tick = update;
Timer_Source = setInterval('addEnemy()', 1000);
}
function update()
{
/* Move Background */
BG.y += 5;
BG2.y += 5;
if(BG.y >= 480)
{
BG.y = -480;
}
else if(BG2.y >= 480)
{
BG2.y = -480;
}
/* Move Bullets */
for(var i = 0; i < Bullets.children.length; i++)
{
Bullets.children[i].y -= 10;
}
/* Clear offstage Bullets */
if(Bullets.children[i].y < - 20)
{
Bullets.removeChildAt(i);
}
}
/* Show Boss */
if(parseInt(Score.text) >= 1000 && Boss1 == null)
{
Boss1 = new Bitmap(Boss1_Img);
SoundJS.play('Boss');
Boss1.x = Center_X - 90;
Boss1.y = -183;
stage.addChild(boss1);
Tween.get(boss1).to({y:40}, 2000) //tween the boss onto the play area
}
/* Move Enemies */
for(var j = 0; j < Enemies.children.length; j++)
{
eEemies.children[j].y += 5;
/* Remove Offstage Enemies */
if(Enemies.children[j].y > 480 + 50)
{
Enemies.removeChildAt(j);
}
}
/* Bullet - Enemy Collision */
for(var k = 0; k < Bullets.children.length; k++)
{
if(Bullets.children[k].x >= Enemies.children[j].x && Bullets.children[k].x + 11 < Enemies.children[j].x + 49 && Bullets.children[k].y < Enemies.children[j].y + 40)
{
Bullets.removeChildAt(k);
Enemies.removeChildAt(j);
stage.update();
SoundJS.play('Shuriken_Hit');
Score.text = parseFloat(Score.text + 50);
}
/* Bullet - Boss Collision */
if(Boss1 != null && bullets.children[k].x >= Boss1.x && Bullets.children[k].x + 11 < Boss1.x + 183 && Bullets.children[k].y < Boss1.y + 162)
{
Bullets.removeChildAt(k);
Boss_Health--;
stage.update();
SoundJS.play('Shuriken_Hit');
Score.text = parseInt(Score.text + 50);
}
}
/* Player1 - Enemy Collision */
if(Enemies.hitTest(Player1.x, Player1.y) || Enemies.hitTest(Player1.x + 37, Player1.y))
{
Enemies.removeChildAt(j);
Lives.removeChildAt(Lives.length);
Player1.y = 480 + 34;
Tween.get(Player1).to({y:425}, 500)
SoundJS.play('Shuriken_Hit');
}
/* Check for win */
if(Boss1 != null && Boss_Health <= 0)
{
alert('Win');
}
/* Check for lose */
if(Lives.children.length <= 0)
{
alert('Lose');
}
function alert(e)
{
/* Remove Listeners */
stage.onMouseMove = null;
BG.onPress = null;
BG2.onPress = null;
Ticker.removeListener(Ticker_Listener);
Ticker_Listener = null;
Timer_Source = null;
/* Display Correct Message */
if(e == 'Win')
{
Win = new Bitmap(Win_Img);
Win.x = centerX - 64;
Win.y = centerY - 23;
stage.addChild(Win);
stage.removeChild(Enemies, Boss1);
}
else
{
Lose = new Bitmap(Lose_Img);
Lose.x = centerX - 64;
Lose.y = centerY - 23;
stage.addChild(Lose);
stage.removeChild(Enemies, Player1);
}
BG.onPress = function(){window.location.reload();};
BG2.onPress = function(){window.location.reload();};
stage.update();
}
Raw HTML Code:
<!doctype html>
<html>
<head>
<title>Scrolling Shooter</title>
<meta charset="utf-8">
<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style>
<link rel="stylesheet" href="Week11.css">
<script src="https://code.createjs.com/easeljs-0.8.1.min.js"></script>
<script src="https://code.createjs.com/tweenjs-0.6.1.min.js"></script>
<script src="https://code.createjs.com/soundjs-0.6.1.min.js"></script>
</head>
<body onload="Main();">
<div id="stage">
<canvas id= "Shooter"> width="1920" height="1080" </canvas>
</div>
<script src="Main.js"> </script>
</body>
</html>
The tutorial you are using is sorely out-of-date (it uses a version of CreateJS that is 3 or 4 years old). The version of EaselJS you are using in your sample was published in May 2015.
To start with, all CreateJS classes (such as Container) need to use the createjs namespace:
Player1 = new createjs.Bitmap(Player1_Img);
Score = new createjs.Text('0', 'bold 14px Courier New', '#FFFFFF');
The Ticker API has also changed:
createjs.Ticker.addEventListener("tick", stage);
// OR
createjs.Ticker.on("tick", stage);
There are also other APIs that have changed (BitmapAnimation became Sprite for example).
I would start there, and then follow up here once you have made some progress. Use your console to determine what errors are happening, and solve them one at a time.
Cheers,
I want to set a new position of body on BeginContact event but it's still not functional. It's writed in JavaSript with drawing to canvas but it doesn't matter for Box2d. In HTML file in body is only empty canvas, nothing else. Here is my code:
In the beginning of JS file are only declarated some variables.
Vec2 = Box2D.Common.Math.b2Vec2;
BodyDef = Box2D.Dynamics.b2BodyDef;
Body = Box2D.Dynamics.b2Body;
FixtureDef = Box2D.Dynamics.b2FixtureDef;
Fixture = Box2D.Dynamics.b2Fixture;
World = Box2D.Dynamics.b2World;
PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
DebugDraw = Box2D.Dynamics.b2DebugDraw;
var player;
It's followed by a setup function which is called in the beginning.
function setup()
{
canvas = document.getElementById("collisionCanvas");
context = canvas.getContext('2d');
document.getElementsByTagName('body')[0].style.backgroundColor = "black";
canvas.style.backgroundColor = "white";
canvas.width = 320;
canvas.height = 320;
world = new World(new Vec2(0, 10), false);
//Point of the problem!!!
//setting contact listener
var listener = new Box2D.Dynamics.b2ContactListener;
listener.BeginContact = function(contact)
{
var body1 = contact.GetFixtureA().GetBody();
var body2 = contact.GetFixtureB().GetBody();
if(body1.GetUserData().type == "player")
{
body1.SetPosition({x:5, y:5});
}
else
{
body2.SetPosition({x:5, y:5});
}
}
world.SetContactListener(listener);
var fixDef = new FixtureDef;
fixDef.density = 1.0;
fixDef.friction = 0.5;
fixDef.restitution = 0.2;
var bodyDef = new BodyDef;
//creating ground
bodyDef.type = Body.b2_staticBody;
bodyDef.position.x = convertPixelsToMeters(160);
bodyDef.position.y = convertPixelsToMeters(320-32/2);
bodyDef.userData = {type: "static"};
fixDef.shape = new PolygonShape;
fixDef.shape.SetAsBox(convertPixelsToMeters(canvas.width/2), convertPixelsToMeters(32/2));
world.CreateBody(bodyDef).CreateFixture(fixDef);
//creating player
bodyDef.type = Body.b2_dynamicBody;
bodyDef.fixedRotation = true;
bodyDef.position.x = convertPixelsToMeters(160);
bodyDef.position.y = convertPixelsToMeters(160);
bodyDef.userData = {type: "player"};
fixDef.shape = new PolygonShape;
fixDef.shape.SetAsBox(convertPixelsToMeters(16), convertPixelsToMeters(16));
player = world.CreateBody(bodyDef);
player.CreateFixture(fixDef);
//setup debug draw
var debugDraw = new DebugDraw();
debugDraw.SetSprite(document.getElementById("collisionCanvas").getContext("2d"));
debugDraw.SetDrawScale(32.0);
debugDraw.SetFillAlpha(0.3);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(DebugDraw.e_shapeBit | DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
window.setInterval(update, 1000 / 60);
}
And in the end are only update function, one helping function and that's it.
function update()
{
world.Step(
1 / 60 //frame-rate
, 10 //velocity iterations
, 10 //position iterations
);
world.DrawDebugData();
world.ClearForces();
}
function convertPixelsToMeters(x)
{
return x*0.03125;
}
$(function(){
setup();
})
Important is only the middle code where is BeginContact event where is calling the SetPosition function which doesn't work.
I tried change position in other places, for example on KeyDown event and there it was correct, so it's for me understandable why it doesn't work.
In the b2Contactlistner method we can not change any prperty or position.
You can take any boolean variable and make it true when in beign contact and if change the position of body according to boolean variable.
as in your code.......
var bodyyy;
var boolennn
listener.BeginContact = function(contact)
{
var body1 = contact.GetFixtureA().GetBody();
var body2 = contact.GetFixtureB().GetBody();
if(body1.GetUserData().type == "player")
{
//body1.SetPosition({x:5, y:5});
bodyyy = body1;
booleannn = true;
}
else
{
// body2.SetPosition({x:5, y:5});
bodyyy = body2;
boolennn = true;
}
}
Now In your Update method
if(booleann)
{
bodyyy.SetPosition({x:5, y:5})
}
SORRY I Donot know syntax of java script
not sure what I'm doing wrong here but some select mouse events (drag/drop, onclick and onpress) do not work. onDoubleClick works however. This is what I'm doing.
.js file
var b2Vec2 = Box2D.Common.Math.b2Vec2;
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
var b2BodyDef = Box2D.Dynamics.b2BodyDef;
var b2Body = Box2D.Dynamics.b2Body;
var b2FixtureDef = Box2D.Dynamics.b2FixtureDef;
var b2Fixture = Box2D.Dynamics.b2Fixture;
var b2World = Box2D.Dynamics.b2World;
var b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape;
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
var b2AABB = Box2D.Collision.b2AABB;
var b2ContactListener = Box2D.Dynamics.b2ContactListener;
window.onblur = function(){ Ticker.setPaused(true); PAUSED = true; console.log("paused"); }
window.onfocus = function(){ Ticker.setPaused(false); PAUSED = false; console.log("unpaused"); }
var PAUSED = false;
var Type = {
WALL : 1,
BOULDER : 2
};
var CategoryBits = {
WALL : 0x0001,
BOULDER : 0x0002
};
function Boundary(density, restitution, friction, angularDamping, linearDamping, position, size, scale, categoryBits, maskBits, type, world){
var boundaryFixture = new b2FixtureDef;
boundaryFixture.density = density;
boundaryFixture.restitution = restitution;
boundaryFixture.friction = friction;
boundaryFixture.filter.categoryBits = categoryBits;
boundaryFixture.filter.maskBits = maskBits;
boundaryFixture.shape = new b2PolygonShape;
boundaryFixture.shape.SetAsBox(size.length/scale, size.height/scale);
var boundaryBodyDef = new b2BodyDef;
boundaryBodyDef.type = b2Body.b2_staticBody;
boundaryBodyDef.angularDamping = angularDamping;
boundaryBodyDef.linearDamping = linearDamping;
boundaryBodyDef.position.x = position.x/ scale;
boundaryBodyDef.position.y = position.y/scale;
this.boundary = world.CreateBody(boundaryBodyDef);
this.boundary.CreateFixture(boundaryFixture);
this.boundary.SetUserData(this);
this.type = type;
};
function Position(x, y){
this.x = x;
this.y = y;
};
function Size(length, height){
this.length = length;
this.height = height;
};
function Noir(size, scale, step, debug){
this.GRAVITY = new b2Vec2(0, 10/(scale/5));
this.FPS = 30;
this.SCALE = scale;
this.STEP = step;
this.TIMESTEP = 1/this.STEP;
this.DEBUG = debug;
this.LENGTH = size.length;
this.LENGTH_OFFSET = 20;
this.HEIGHT = size.height;
this.HEIGHT_OFFSET = 10;
this.BOUNDARY_WIDTH = 2;
this.VELOCITY_ITERATIONS = 10;
this.POSITION_ITERATIONS = 10;
this.world;
this.contactListener;
this.canvas;
this.debugCanvas;
this.debugDraw;
this.context;
this.debugContext;
this.stage;
this.previousTime = Date.now();
this.game;
};
Noir.prototype.initCanvas = function(){
this.canvas = document.getElementById('canvas');
this.context = canvas.getContext('2d');
this.stage = new Stage(canvas);
this.stage.snapPixelsEnabled = true;
this.stage.mouseEventsEnabled = true;
//this.stage.onDoubleClick = function(event){ console.log("moving.."); }
this.stage.enableMouseOver();
if(this.DEBUG){
this.debugCanvas = document.getElementById('debugCanvas');
this.debugContext = debugCanvas.getContext('2d');
console.log('Debug on');
}
};
Noir.prototype.initDebug = function(){
this.debugDraw = new b2DebugDraw();
this.debugDraw.SetSprite(this.debugContext);
this.debugDraw.SetDrawScale(this.SCALE);
this.debugDraw.SetFillAlpha(0.7);
this.debugDraw.SetLineThickness(1.0);
this.debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
this.world.SetDebugDraw(this.debugDraw);
};
Noir.prototype.setContactListener = function(){
this.contactListener = new b2ContactListener;
this.contactListener.events = this;
this.contactListener.BeginContact = function(contact, manifold){
var bodyAUser = contact.GetFixtureA().GetBody().GetUserData();
var bodyBUser = contact.GetFixtureB().GetBody().GetUserData();
/* console.log(bodyAUser.type + " , " + bodyBUser.type); */
if((bodyAUser.type == Type.BOULDER) && (bodyBUser.type == Type.WALL)){ this.events.boulderWallContact(bodyAUser, bodyBUser); }
else if((bodyAUser.type == Type.WALL) && (bodyBUser.type == Type.BOULDER)){ this.events.boulderWallContact(bodyBUser, bodyAUser); }
}
this.world.SetContactListener(this.contactListener);
};
Noir.prototype.boulderWallContact = function(boulder, wall){ boulder.flagToDestroy(); };
Noir.prototype.initPhysics = function(){
this.lastTimestamp = Date.now();
this.world = new b2World(this.GRAVITY, true);
this.setContactListener();
if(this.DEBUG){ this.initDebug(); console.log('Debug initialized'); }
var floor = new Boundary(1, 1, 0.6, 0.6, 0.6, new Position(-(this.LENGTH_OFFSET/2), (this.HEIGHT+ (this.HEIGHT_OFFSET - (this.HEIGHT_OFFSET - 1)))),
new Size((this.LENGTH + this.LENGTH_OFFSET), this.BOUNDARY_WIDTH), this.SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world);
/* var ceiling = new Boundary(1, 1, 0.6, 0.6, 0.6, new Position(-(this.LENGTH_OFFSET/2), (this.HEIGHT_OFFSET - (this.HEIGHT_OFFSET - 1))),
new Size((this.LENGTH + this.LENGTH_OFFSET), this.BOUNDARY_WIDTH), this.SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world); */
var leftFixture = new Boundary(1,1, 0.6, 0.6, 0.6, new Position(-(this.BOUNDARY_WIDTH - (this.BOUNDARY_WIDTH - 1)), -(this.LENGTH_OFFSET/2)),
new Size(this.BOUNDARY_WIDTH, (this.HEIGHT + this.HEIGHT_OFFSET)), this. SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world);
var rightFixture = new Boundary(1,1, 0.6, 0.6, 0.6, new Position((this.LENGTH + (this.LENGTH_OFFSET - (this.LENGTH_OFFSET - 1))), -(this.LENGTH_OFFSET/2)),
new Size(this.BOUNDARY_WIDTH, (this.HEIGHT+ this.HEIGHT_OFFSET)), this.SCALE, CategoryBits.WALL, CategoryBits.BOULDER, Type.WALL, this.world);
};
Noir.prototype.tick = function(){
this.updatePhysics();
this.stage.update();
};
Noir.prototype.initTicker = function(){
Ticker.setFPS(this.FPS);
Ticker.useRAF = true;
Ticker.addListener(this, true);
};
Noir.prototype.init = function(){
this.initCanvas();
this.initTicker();
this.initPhysics();
this.initGame(this.stage, this.world);
var debug = document.getElementById('debug');
};
Noir.prototype.initOnLoadDocument = function(){
console.log('running');
if(document.loaded){ this.init(); }
else{
if(window.addEventListener){ window.addEventListener('load', this.init(), false); }
else { window.attachEvent('onLoad', this.init); }
}
}
Noir.prototype.updatePhysics = function(){
/* remove flagged objects for destruction */
/* update non-flagged objects */
if(!PAUSED){
this.updateGame();
this.world.Step(this.TIMESTEP, this.VELOCITY_ITERATIONS, this.POSITION_ITERATIONS);
this.world.ClearForces();
if(this.DEBUG){
this.world.m_debugDraw.m_sprite.graphics.clear();
this.world.DrawDebugData();
}
}
};
Noir.prototype.initGame = function(){
this.game = new Game(this.stage, this.SCALE, this.world);
this.game.start();
};
Noir.prototype.updateGame = function(){ this.game.update(); }
function Actor(density, restitution, friction, angularDamping, linearDamping, path, position, size, stage, scale, categoryBits, maskBits, type, world){
this.skin = new Bitmap(path);
this.skin.x = position.x;
this.skin.y = position.y;
this.skin.regX = (size.length/2);
this.skin.regY = (size.height/2);
this.skin.snapToPixel = true;
this.skin.mouseEnabled = false;
stage.addChild(this.skin);
var actorFixture = new b2FixtureDef;
actorFixture.density = density;
actorFixture.restitution = restitution;
actorFixture.friction = friction;
actorFixture.filter.categoryBits = categoryBits;
actorFixture.filter.maskBits = maskBits;
actorFixture.shape = new b2PolygonShape;
actorFixture.shape.SetAsBox((size.length/2)/scale, (size.height/2)/scale);
var actorBodyDef = new b2BodyDef;
actorBodyDef.type = b2Body.b2_dynamicBody;
actorBodyDef.angularDamping = angularDamping;
actorBodyDef.linearDamping = linearDamping;
actorBodyDef.position.x = this.skin.x/scale;
actorBodyDef.position.y = this.skin.y/scale;
this.body = world.CreateBody(actorBodyDef);
this.body.CreateFixture(actorFixture);
this.body.SetUserData(this);
this.type = type;
this.destroy = false;
};
Actor.prototype.flagToDestroy = function(){ this.destroy = true; };
Actor.prototype.remove = function(game){
game.stage.removeChild(this.skin);
game.world.DestroyBody(this.body);
game.actors.splice(game.actors.indexOf(this),1);
};
Actor.prototype.update = function(scale){
this.skin.rotation = this.body.GetAngle() * (180/Math.PI);
this.skin.x = this.body.GetWorldCenter().x * scale;
this.skin.y = this.body.GetWorldCenter().y * scale;
};
function Icon(path, position, size, stage){
this.skin = new Bitmap(path);
this.skin.x = position.x;
this.skin.y = position.y;
this.skin.regX = (size.length/2);
this.skin.regY = (size.height/2);
stage.addChild(this.skin);
//this.skin.onDoubleClick = function(event){ alert("click click"); }
this.skin.onClick = function(event){ alert("click"); }
this.skin.onPress = function(event){ console.log("pressing"); }
};
function Game(stage, scale, world){
this.scale = scale;
this.stage = stage;
this.world = world;
this.boulderSpawnDelayCounter = 0;
this.actors = [];
this.icon;
};
Game.prototype.start = function(){
var position = new Position(400, 200);
var size = new Size(50, 50);
console.log(this);
this.icon = new Icon("images/bird.png", position, size, this.stage);
};
Game.prototype.controlledSpawn = function(stage, scale, world){
var spawnInterval = (50 + Math.round(Math.random() * 10));
this.boulderSpawnDelayCounter++;
if(this.boulderSpawnDelayCounter % spawnInterval === 0){
this.boulderSpawnDelayCounter = 0;
this.boulderSpawn();
}
};
Game.prototype.boulderSpawn = function(stage, scale, world){
var position = new Position((100 + Math.round(Math.random() * 250)), -20);
var size = new Size(50, 50);
this.actors.push(new Actor(0.2, 0.6, 0.3, 0.3, 0.3, "images/bird.png", position, size, this.stage, this.scale, CategoryBits.BOULDER, CategoryBits.WALL, Type.BOULDER, this.world));
};
Game.prototype.update = function(){
this.controlledSpawn();
for(idx = 0; idx < this.actors.length; ++idx){
if(this.actors[idx].destroy == true){ this.actors[idx].remove(this); }}
for(idx = 0; idx < this.actors.length; ++idx){ this.actors[idx].update(this.scale); }
};
.html file
<!doctype html>
<html xmlns:og="http://ogp.me/ns#">
<head>
<meta charset="utf-8">
<title>Noir test</title>
<link href="css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<canvas width="500" height="500" id="canvas"></canvas>
<canvas width="500" height="500" id="debugCanvas"></canvas>
<script> var createjs = window </script>
<script type="text/javascript" src="libs/easeljs-0.5.0.min.js"></script>
<script type="text/javascript" src="libs/Box2dWeb-2.1.a.3.min.js"></script>
<script type="text/javascript" src="js/noir.js"></script>
<script> var noir = new Noir(new Size(500, 500), 30, 20, false); noir.initOnLoadDocument()</script>
</body>
</html>
I'm working with this on a local server so the server security issue triggering this similar behaviour for remote servers doesn't apply (I think). Guys, I'm stumped here. Your help will be very much appreciated. Thanks.
Without seeing your CSS, I would guess that your debug canvas is layered overtop of your main canvas. If this is the case, the debug canvas will be the target for any mouse events, preventing your main canvas (and the related Stage) from receiving them.
Due to a bug (recently fixed in the NEXT version), EaselJS subscribes to double click events on the window, instead of on the canvas, which is likely why onDoubleClick is working for you.
Also, it might be worth checking out the newer version of EaselJS. v0.7.0 includes a great new event model, and v0.7.1 will be out shortly with the fix for double click.
I am trying to get the distance between my character and the ground, I have found something that looks like it should do what I want but it has been written for another version of box2d.
Original:
float targetHeight = 3;
float springConstant = 100;
//make the ray at least as long as the target distance
b2Vec2 startOfRay = m_hovercarBody->GetPosition();
b2Vec2 endOfRay = m_hovercarBody->GetWorldPoint( b2Vec2(0,-5) );
overcarRayCastClosestCallback callback;
m_world->RayCast(&callback, startOfRay, endOfRay);
if ( callback.m_hit ) {
float distanceAboveGround = (startOfRay - callback.m_point).Length();
//dont do anything if too far above ground
if ( distanceAboveGround < targetHeight ) {
float distanceAwayFromTargetHeight = targetHeight - distanceAboveGround;
m_hovercarBody->ApplyForce( b2Vec2(0,springConstant*distanceAwayFromTargetHeight),
m_hovercarBody->GetWorldCenter() );
}
}
I have tried to change it to what I think it should be but it doesn't even call the callback.
var targetHeight = 3;
var springConstant = 100;
//make the ray at least as long as the target distance
startOfRay = new b2Vec2(m_hovercarBody.GetPosition());
endOfRay = new b2Vec(m_hovercarBody.GetWorldPoint( b2Vec2(0,-5)));
function callback(raycast){
if ( raycast.m_hit ) {
var distanceAboveGround = (startOfRay - raycast.m_point).Length();
//dont do anything if too far above ground
if ( distanceAboveGround < targetHeight ) {
var distanceAwayFromTargetHeight = targetHeight - distanceAboveGround;
m_hovercarBody.ApplyForce( b2Vec2(0,springConstant*distanceAwayFromTargetHeight),
m_hovercarBody.GetWorldCenter() );
}
}
}
m_world.RayCast(callback, startOfRay, endOfRay);
Any idea how to convert it to work with box2dweb?
Thanks
It might be that the original bit of code was written for a platform where the coordinate system works differently.
In a Canvas element, the coordinate system starts from the top left corner, meaning that m_hovercarBody.GetWorldPoint( b2Vec2(0,-5)) is checking for a point above the character, rather than below.
I'm not sure about the rest of the code but try changing that to m_hovercarBody.GetWorldPoint( b2Vec2(0,5)) and see what happens.
EDIT:
I think actually the problem is with the way you've structured your callback. Looking up the reference for the Raycast function would reveal more.
(The Javascript version of Box2D you're using is an automatic port of the Actionscript one. Given the two have fairly similar syntax, you can use the reference for Flash.)
The original code you posted seems to be C++, but I don't know much about its syntax. It seems there's some sort of class that does the raycasting (overcarRayCastClosestCallback). You can either look for that, or try and build your own callback function according to the first link I posted. It would be something along the lines of:
function customRaycastCallback(fixture, normal, fraction) {
// you can, for instance, check if fixture belongs to the ground
// or something else, then handle things accordingly
if( /* fixture belongs to ground */ ) {
// you've got the fraction of the original length of the raycast!
// you can use this to determine the distance
// between the character and the ground
return fraction;
}
else {
// continue looking
return 1;
}
}
Try running this on your browser. I coded this when I was learning sensor and RAYCAST in Box2Dweb. Hope it helps.
<html>
<head>
<title>Box2dWeb Demo</title>
</head>
<body>
<canvas id="canvas" width="600" height="420" style="background-color:#333333;" ></canvas>
<div id="cc" style="position:absolute; right:0; top:100px; width:500px; height:50px; margin:0;"></div>
</body>
<script type="text/javascript" src="Box2dWeb-2.1.a.3.js"></script>
<script type="text/javascript" src="jquery-1.7.2.js"></script>
<script type="text/javascript">
var b2Vec2 = Box2D.Common.Math.b2Vec2
, b2BodyDef = Box2D.Dynamics.b2BodyDef
, b2Body = Box2D.Dynamics.b2Body
, b2FixtureDef = Box2D.Dynamics.b2FixtureDef
, b2World = Box2D.Dynamics.b2World
, b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
, b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
, b2ContactFilter = Box2D.Dynamics.b2ContactFilter
, b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef
, b2DebugDraw = Box2D.Dynamics.b2DebugDraw
, b2Fixture = Box2D.Dynamics.b2Fixture
, b2AABB = Box2D.Collision.b2AABB
, b2WorldManifold = Box2D.Collision.b2WorldManifold
, b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint
, b2RayCastInput = Box2D.Collision.b2RayCastInput
, b2RayCastOutput = Box2D.Collision.b2RayCastOutput
, b2Color = Box2D.Common.b2Color;
var world = new b2World(new b2Vec2(0,10), true);
var canvas = $('#canvas');
var context = canvas.get(0).getContext('2d');
//box
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(9,7);
bodyDef.userData = 'box';
var fixDef = new b2FixtureDef;
fixDef.filter.categoryBits = 1;
fixDef.density = 10.0;
fixDef.friction = 0.5;
fixDef.restitution = .5;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(1,5);
var box1 = world.CreateBody(bodyDef);
box1.CreateFixture(fixDef);
//circle
var bodyDef2 = new b2BodyDef;
bodyDef2.type = b2Body.b2_dynamicBody;
bodyDef2.position.Set(4,8);
bodyDef2.userData = 'obj';
var fixDef2 = new b2FixtureDef;
fixDef2.filter.categoryBits = 2;
fixDef2.filter.maskBits = 13;
fixDef2.density = 10.0;
fixDef2.friction = 0.5;
fixDef2.restitution = .2;
fixDef2.shape = new b2CircleShape(1);
//circlesensor
var cc = new b2FixtureDef;
cc.shape = new b2CircleShape(2);
cc.shape.SetLocalPosition(new b2Vec2(0 ,0));
cc.density = 0;
cc.isSensor = true;
cc.filter.categoryBits = 8;
var wheel = world.CreateBody(bodyDef2);
wheel.CreateFixture(fixDef2);
wheel.CreateFixture(cc);
//create a ground
var holderDef = new b2BodyDef;
holderDef.type = b2Body.b2_staticBody;
holderDef.userData = "ground";
holderDef.position.Set(10, 14);
var fd = new b2FixtureDef;
fd.filter.categoryBits = 4;
fd.shape = new b2PolygonShape;
fd.shape.SetAsBox(10,1);
var ground = world.CreateBody(holderDef);
ground.CreateFixture(fd);
//create another static body
var holderDef = new b2BodyDef;
holderDef.type = b2Body.b2_staticBody;
holderDef.position.Set(10, 20);
var temp = world.CreateBody(holderDef);
temp.CreateFixture(fd);
var c=0;
$(window).keydown(function(e) {
$('#aa').html(++c);
code = e.keyCode;
if(c==1) {
if(code == 38 && onground)
wheel.SetLinearVelocity(new b2Vec2(0,-10));
if(code == 39)
wheel.ApplyForce(new b2Vec2(1000,0), box1.GetWorldPoint(new b2Vec2(0,0)));
if(code == 37)
wheel.ApplyForce(new b2Vec2(-1000,0), box1.GetWorldPoint(new b2Vec2(0,0)));
}
});
$(window).keyup(function(e) {
c=0;
});
var listener = new Box2D.Dynamics.b2ContactListener;
listener.BeginContact = function(contact) {
if(contact.GetFixtureA().GetBody().GetUserData()== 'obj' || contact.GetFixtureB().GetBody().GetUserData()== 'obj' ) // think about why we don't use fixture's userData directly.
onground = true;// don't put 'var' here!
fxA=contact.GetFixtureA();
fxB=contact.GetFixtureB();
sA=fxA.IsSensor();
sB=fxB.IsSensor();
if((sA && !sB) || (sB && !sA)) {
if(sA) {
$('#cc').prepend(contact.GetFixtureB().GetBody().GetUserData() + ' is in the viscinity of body '+contact.GetFixtureA().GetBody().GetUserData()+'<br>');
}
else {
$('#cc').prepend(contact.GetFixtureA().GetBody().GetUserData() + ' is in the viscinity of body '+contact.GetFixtureB().GetBody().GetUserData()+'<br>');
}
}
}
listener.EndContact = function(contact) {
if (contact.GetFixtureA().GetBody().GetUserData()== 'obj' || contact.GetFixtureB().GetBody().GetUserData()== 'obj' )
onground = false;
}
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite ( document.getElementById ("canvas").getContext ("2d"));
debugDraw.SetDrawScale(30); //define scale
debugDraw.SetAlpha(1);
debugDraw.SetFillAlpha(.3); //define transparency
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
window.setInterval(update,1000/60);
//mouse
var mouseX, mouseY, mousePVec, isMouseDown, selectedBody, mouseJoint;
var canvasPosition = getElementPosition(document.getElementById("canvas"));
document.addEventListener("mousedown", function(e) {
isMouseDown = true;
handleMouseMove(e);
document.addEventListener("mousemove", handleMouseMove, true);
}, true);
document.addEventListener("mouseup", function() {
document.removeEventListener("mousemove", handleMouseMove, true);
isMouseDown = false;
mouseX = undefined;
mouseY = undefined;
}, true);
function handleMouseMove(e) {
mouseX = (e.clientX - canvasPosition.x) / 30;
mouseY = (e.clientY - canvasPosition.y) / 30;
};
function getBodyAtMouse() {
mousePVec = new b2Vec2(mouseX, mouseY);
var aabb = new b2AABB();
aabb.lowerBound.Set(mouseX - 0.001, mouseY - 0.001);
aabb.upperBound.Set(mouseX + 0.001, mouseY + 0.001);
// Query the world for overlapping shapes.
selectedBody = null;
world.QueryAABB(getBodyCB, aabb);
return selectedBody;
}
function getBodyCB(fixture) {
if(fixture.GetBody().GetType() != b2Body.b2_staticBody) {
if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), mousePVec)) {
selectedBody = fixture.GetBody();
return false;
}
}
return true;
}
//at global scope
var currentRayAngle = 0;
var input = new b2RayCastInput();
var output = new b2RayCastOutput();
var b = new b2BodyDef();
var f = new b2FixtureDef();
var closestFraction = 1;
var intersectionNormal = new b2Vec2(0,0);
var intersectionPoint = new b2Vec2();
rayLength = 25; //long enough to hit the walls
var p1 = new b2Vec2( 11, 7 ); //center of scene
var p2 = new b2Vec2();
var normalEnd = new b2Vec2();
function update() {
if(isMouseDown && (!mouseJoint)) {
var body = getBodyAtMouse();
if(body) {
var md = new b2MouseJointDef();
md.bodyA = world.GetGroundBody();
md.bodyB = body;
md.target.Set(mouseX, mouseY);
md.collideConnected = true;
md.maxForce = 300.0 * body.GetMass();
mouseJoint = world.CreateJoint(md);
body.SetAwake(true);
}
}
if(mouseJoint) {
if(isMouseDown) {
mouseJoint.SetTarget(new b2Vec2(mouseX, mouseY));
} else {
world.DestroyJoint(mouseJoint);
mouseJoint = null;
}
}
world.Step(1 / 60, 10, 10);
world.DrawDebugData();
world.ClearForces();
world.SetContactListener(listener);
ray();
};
function ray() {
//in Step() function
var k = 360/20;
var t = k/60;
var DEGTORAD = Math.PI/180;
currentRayAngle += t * DEGTORAD; //one revolution every 20 seconds
//console.log(currentRayAngle*(180/Math.PI));
//calculate points of ray
p2.x = p1.x + rayLength * Math.sin(currentRayAngle);
p2.y = p1.y + rayLength * Math.cos(currentRayAngle);
input.p1 = p1;
input.p2 = p2;
input.maxFraction = 1;
closestFraction = 1;
var b = new b2BodyDef();
var f = new b2FixtureDef();
for(b = world.GetBodyList(); b; b = b.GetNext()) {
for(f = b.GetFixtureList(); f; f = f.GetNext()) {
if(!f.RayCast(output, input))
continue;
else if(output.fraction < closestFraction) {
closestFraction = output.fraction;
intersectionNormal = output.normal;
}
}
}
intersectionPoint.x = p1.x + closestFraction * (p2.x - p1.x);
intersectionPoint.y = p1.y + closestFraction * (p2.y - p1.y);
normalEnd.x = intersectionPoint.x + intersectionNormal.x;
normalEnd.y = intersectionPoint.y + intersectionNormal.y;
context.strokeStyle = "rgb(255, 255, 255)";
context.beginPath(); // Start the path
context.moveTo(p1.x*30,p1.y*30); // Set the path origin
context.lineTo(intersectionPoint.x*30, intersectionPoint.y*30); // Set the path destination
context.closePath(); // Close the path
context.stroke();
context.beginPath(); // Start the path
context.moveTo(intersectionPoint.x*30, intersectionPoint.y*30); // Set the path origin
context.lineTo(normalEnd.x*30, normalEnd.y*30); // Set the path destination
context.closePath(); // Close the path
context.stroke(); // Outline the path
}
//helpers
//http://js-tut.aardon.de/js-tut/tutorial/position.html
function getElementPosition(element) {
var elem=element, tagname="", x=0, y=0;
while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) {
y += elem.offsetTop;
x += elem.offsetLeft;
tagname = elem.tagName.toUpperCase();
if(tagname == "BODY")
elem=0;
if(typeof(elem) == "object") {
if(typeof(elem.offsetParent) == "object")
elem = elem.offsetParent;
}
}
return {x: x, y: y};
}
</script>
</html>
Here's a Raycast in Box2dWeb that I got working:
var p1 = new b2Vec2(body.GetPosition().x, body.GetPosition().y); //center of scene
var p2 = new b2Vec2(body.GetPosition().x, body.GetPosition().y + 5); //center of scene
world.RayCast(function(x){
console.log("You've got something under you");
}, p1,p2);