Simple general rayCasting in box2d Javascript example - javascript

I've been looking through various tutorials on rayCasting with Box2D, but I haven't seen any clear examples. I was hoping someone familiar with box2dweb would be able to give a clear example of how one would go about setting up a simple function that would end up looking something like this:
var myRayCastFunction = function(p1,p2,maxFraction){
//Code here
}
The idea being that it would be usable like this:
var retVal = myRayCastFunction(p1,p2,maxFraction)
var fixture = retVal.fixture
var point = retVal.point
var normal = retVal.normal
var fraction = retVal.fraction
(in this case, I'm simply returning 1 intersection, say the nearest one, but would want to know how to make a similar one where retVel is a list of these outputs for each intersection)
I've been trying to understand all of the details of how RayCasting works in box2D, and I understand that this requires making a custom callback function (I think?), but I never figured out where that function needs to be placed, and what IT should be as well.

I started to answer this question because I happened to be about to add raycasting to my current project, and I realized there were actually some bugs in box2dweb that needed to be fixed before I could get it done. I'll link to the details instead of cluttering up this post:
http://www.iforce2d.net/box2dweb-fixes.txt
Here is how I've used the raycast callback successfully. Declare your callback class and give it a ReportFixture function:
var RaycastCallback = function() {
this.m_hit = false;
}
RaycastCallback.prototype.ReportFixture = function(fixture,point,normal,fraction) {
if ( ... not interested in this fixture ... )
return -1;
this.m_hit = true;
this.m_point = point;
this.m_normal = normal;
return fraction;
};
Now make an instance of that to pass to the worlds RayCast function:
var rayStart = ...;
var rayEnd = ...;
var callback = new RaycastCallback();
world.RayCast(callback, rayStart, rayEnd);
if ( callback.m_hit ) {
... use callback.m_point etc ...
}

Related

Javascript: Can't handle events for multiple instances

I have put together a fun API for game creation. In the code I create a prototype for Mover and then extend it with several specific prototypes (Gold, Monster, and Hero). Each one is based on a img tag with a given ID. I use type-specific information in the constructor and a single template method for each type. Most of the functional code in Mover depends on those type-specific details. I have included one example for simplicity.
I use method calls in a separate script to create and destroy instances of the Mover child types. When I create and destroy one instance at a time everything works as intended. The image updates, the sound plays and it is removed after the correct delay. If I create two or more, however, only the last one works as expected. So if I make gold, moster, hero. Only the hero will remove correctly. The other two will play the audio, but don't appear to update.
I ran into the same problem when I tried to attach a function to the onclick event for more than one instance. Only the last one worked and the others did nothing. Obviously I'm missing something about the way java handles method assignments. Any explanation you can offer would help.
Thanks,
BSD
function Mover()
{
}
Mover.prototype.InitTag = function()
{
this.HTMLtag.src=this.imageURL;
this.HTMLtag.style.position="absolute";
this.HTMLtag.style.width=characterSize;
this.HTMLtag.style.height=characterSize;
this.Position(Math.floor(Math.random()*(MaxW-characterSize)+(characterSize/2)),Math.floor(Math.random()*(MaxH-characterSize)+(characterSize/2)));
}
Mover.prototype.Destroy = function()
{
var disp = this.HTMLtag.display;
this.HTMLtag.src=this.destroyURL
this.HTMLtag.display = disp;
this.destroyAudio.play();
this.RemoveTag();
}
function Monster(id)
{
this.MonsterID = id;
this.HTMLtag = document.getElementById("monster"+id);
this.imageURL = "monster1.jpg";
this.destroyURL = "monster2.jpg";
this.destroyAudio = monsterAudio;
}
Monster.prototype = new Mover();
Monster.prototype.RemoveTag = function()
{
var mID = this.MonsterID;
setTimeout(function() {field.DeleteMonster(mID)}, 1000);
}
function Hero()
{
this.HTMLtag = document.getElementById("hero");
this.imageURL = "hero1.jpg";
this.destroyURL = "hero2.jpg";
this.destroyAudio = heroAudio;
}
Hero.prototype = new Mover();
Hero.prototype.RemoveTag = function()
{
setTimeout(function() {field.DeleteHero()}, 5000);
}
function Gold(id)
{
this.GoldID = id;
this.HTMLtag = document.getElementById("gold"+id);
this.imageURL = "gold1.jpg";
this.destroyURL = "gold2.jpg";
this.destroyAudio = goldAudio;
}
Gold.prototype = new Mover();
Gold.prototype.RemoveTag = function()
{
var mID = this.GoldID;
setTimeout(function() {field.DeleteGold(mID)}, 1000);
}
---------UPDATE UPDATE UPDATE-----------
I have at least partially fixed the problem. I have gotten it to work, but I still don't know why it didn't function as intended. I noticed that while my browser's (Chrome) developer tools could visually identify the most-recently-added Mover when it was being destroyed, it could not do so with the any other movers.
Tag of most recently added Mover can be identified in Chrome developer tools.
This suggested that Mover.HTMLtag was not actually the same as document.getElementById('mover1'). I was able to confirm this by looking at the variables in the GoldField.DeleteMover. At the line indicated mover.src has not changed, but movers[id].HTMLtag.src has been correctly updated. In the most-recently-added case they were both the same.
GoldField.prototype.DeleteMover = function(id)
{
var isHero = false;
if(this.Hero!=null && id==this.Hero.myID)
{
this.Hero = null;
isHero = true;
}
else if(this.Tower!=null && id==this.Tower.myID)
{
this.Tower = null;
}
var mover = document.getElementById("mover"+id);
if(!isHero)
{
this.tag.removeChild(mover);//<<< HERE HERE HERE HERE
delete this.movers[id];
}
}
So, I changed one line in Mover.Destroy. By finding the tag by ID and setting the src. I was able to reliable behavior. It would appear that Mover.HTMLtag is not reliable the same after the second Mover is added. Any explanation?
Mover.prototype.Destroy = function()
{
document.getElementById(this.HTMLtag.id).src=this.destroyURL;
this.HTMLtag.src=this.destroyURL;//old method
this.destroyAudio.play();
this.RemoveTag();
}
On suspicion that this might extend to other updates to this.HTMLtag I set up some basic movement of the Hero. It works great, but if you add one additional Mover of any kind it no longer moves. That narrows down the question considerably. Why would constructing a second Mover cause the prototype members to change?
So I debug your code and I found the cause of your problem. The problem was when you create a new instance of monster you storing a reference to it on the monster var. And when you delete it you don't delete / update the reference to it. So your delete function myField.DeleteMover(id) try to delete a monster already deleted. How to solve this.
// create an array to keep ref to our instances
var monsters= [];
// var monster = null;
function addMonster()
{
// monster = goldField.AddMonster();⏎
// push every monster in array
monsters.push(goldField.AddMonster());
}
function killMonster()
{
// if array.length is true
if (monsters.length) {
// call the destroy function on the last ref
monsters[monsters.length - 1].Destroy();
// remove the last ref from array using pop
monsters.pop();
}
//monster.Destroy();
}
This is working however I think all of this should be done in the objects itself. And you should not care about it here.
Another advice try to use more array methods. Avoid using delete on array index because it mess with index and count instead use splice(index, 1) same for add item in array use push instead of arbitrary index.
Anyway funny game! Good luck to finish it.
Edit, after your answer I go back an test.
To make it work I do this.
// First go inGoldField.prototype.DeleteMover and replace the ugly delete index by
this.movers.splice(id, 1);
// Then in the Mover.prototype.Destroy
// This part is a a little blurred for me.
// the current HTMLtag looks good but when I console.log like this
console.log('before', this.HTMLtag);
this.HTMLtag = document.querySelector("#mover" + this.myID);
console.log('after', this.HTMLtag);
// They are not equal look like the first is outdated
You should convert all your delete and add to splice and push methods.
This is just a quick debug I don't know why the selector is outdated.
So I check the code again and I make it work without refreshing the selector. The problem is caused by the creation of dom element with innerHTML.
First reset
this.HTMLtag.src=this.destroyURL
Then instead of
//Mover.prototype.Destroy
this.tag.innerHTML+="<img id='mover"+this.moverCount+"'>";
I create a img dom el.
var img = document.createElement("img");
img.setAttribute('id', 'mover' + this.moverCount);
this.tag.appendChild(img);
All Monsters are now deleted with the image.
I don't check for the hero but first you should update your innerHTML and reply if there is still a problem. I don't think there is any problem with some prototype.

Can I put a CollaborativeString inside a custom type?

I'm reading the Google Drive Realtime API documentation on Building a Collaborative Data Model.
I really like the way gapi.drive.realtime.databinding.bindString behaves. It doesn't mess up your cursor placement when multiple people are typing in the same text box. But it requires that you pass it a CollaborativeString.
But if you register a custom type, you have to use gapi.drive.realtime.custom.collaborativeField no matter what type of field you are defining, and you can't pass one of these to bindString. In fact, the collaborativeField type does not appear to be documented anywhere, and inspecting it in the console shows that it has no methods. That means there's no registerReference method, which CollaborativeString uses to keep track of cursor positions.
How frustrating. So I guess I have to work around it. I see a few options:
Ignore the fact that the cursor gets messed up during collaboration
Use a CollaborativeMap instead of a custom type, and wrap it with my custom type at runtime
Probably going to do option 2.
I think you misunderstand how this site works, the onus is not on other people to show you how to do something - you're asking other people to take time from their day and help you.
That being said, taking a quick look at the page that you linked shows that what you want to do is not only possible but quite straightforward and compatible with bindString. Stealing from the example code from that page:
// Call this function before calling gapi.drive.realtime.load
function registerCustomTypes()
{
var Book = function () { };
function initializeBook()
{
var model = gapi.drive.realtime.custom.getModel(this);
this.reviews = model.createList();
this.content = model.createString();
}
gapi.drive.realtime.custom.registerType(Book, 'Book');
Book.prototype.title = gapi.drive.realtime.custom.collaborativeField('title');
Book.prototype.author = gapi.drive.realtime.custom.collaborativeField('author');
Book.prototype.isbn = gapi.drive.realtime.custom.collaborativeField('isbn');
Book.prototype.isCheckedOut = gapi.drive.realtime.custom.collaborativeField('isCheckedOut');
Book.prototype.reviews = gapi.drive.realtime.custom.collaborativeField('reviews');
Book.prototype.content = gapi.drive.realtime.custom.collaborativeField('content');
gapi.drive.realtime.custom.setInitializer(Book, initializeBook);
}
and
// Pass this as the 2nd param to your gapi.drive.realtime.load call
function onDocLoaded(doc)
{
var docModel = doc.getModel();
var docRoot = docModel.getRoot();
setTimeout(function ()
{
var book = docModel.create('Book');
book.title = 'Moby Dick';
book.author = 'Melville, Herman';
book.isbn = '978-1470178192';
book.isCheckedOut = false;
book.content.setText("Call me Ishmael. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.");
docRoot.set('tbook', book);
debugger;
}, 0);
}
Good luck and have fun with the Realtime API - it's a lot of fun to play with.
I know this question and answer are getting old, but for reference's sake, just the last part of Grant Watters' very good answer, the onDocLoaded routine, is rather misleading. That function as written, is more suited for the 3rd parameter to the gapi.drive.realtime.load call, the onInitializeModel callback.
The 2nd parameter is called every time the Doc is loaded. You wouldn't normally add the same object over and over as the above routine would... Instead, you would normally set up your event handling, your dataBinds etc. This version might clarify somewhat:
// Pass this as the 2nd param to your gapi.drive.realtime.load call
function onDocLoaded(doc)
{
var docModel = doc.getModel();
var docRoot = docModel.getRoot();
var text = doc.getModel().getRoot().get("text");
// Add an event listener...
text.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, onStringChanged);
// ...and/or bind to collaborative objects:
var textArea = document.getElementById('textArea1')
textBinding = gapi.drive.realtime.databinding.bindString(text, textArea);
etc...
}
Not incidentally, bindString returns the binding object, which is needed to "unbind" later, preventing an AlreadyBound error or other unexpected behavior when the next Doc is loaded. Do something like this:
function onDocLoaded(doc)
{
// Clear any previous bindings etc:
if (textBinding) { textBinding.unbind() };
textBinding = null;
etc...

using values from asyncronius function in syncronius function

First, please excuse my bad English. I'm not use to write in English.
I'm using Node.js and i have variables that sometimes get their value from async functions and sometimes by direct assignment (ex:
async(function(data) {
var x= data.something
}; or x = 5;)
the problem is that later on the have shared code which forces me to duplicate the code.
in syncronius scripting i usually do an if.. else statement to seperate the cases and assign. ex:
if(boolivar){
var x = niceFunc();
}
else {
var x = 5;
}
coolFunc(x);
now days im forced to to this:
if(boolivar){
niceFUnc(function(X){
coolFunc(X);
}
}
else{
var x = 5;
coolFunc(X);
}
does someone has an idea how to solve my problem?
I thought about forcing the async function to be sync but:
a. i dont know how
b. it kind of ruins the whole point
I would do it essentially as you have, except that I would abstract the sync/async calls so that it doesn't make any difference to the code that's using it what's really happening behind the scenes (ignore the bad function names; I have no idea what your code does):
function doNiceFunc(boolivar, callback) {
if (boolivar) {
niceFUnc(function(x) {
callback(x);
});
} else {
callback(5);
}
}
Now doNiceFunc appears the same in both cases from the outside:
doNiceFunc(boolivar, function(x) {
coolFunc(x);
});
I've used this exact pattern in a library that retrieved data that was sometimes immediately available and other times had to be retrieved from the network. The users of this library didn't have to care which was the case at any given time, because the call looked the same in both situations.
I tend to use this lib node-sync
var sync = require('sync');
sync(function(){
var result = query.sync(query, params);
// result can be used immediately
})

Raphael js drag inside javascript object

I had a little problem today and thought I could try stack overflow. I'll be short and sweet (I removed lot of code to make this clear).
I recently discovered raphaeljs and I like it.
I make some circle draggable and it works fine like this:
Working script:
<script>
var paper = Raphael(100,100,500,500);
var circ = paper.circle(50,50,10)
var start = function(){ };
var move = function(dx,dy)
{
this.attr({cx: this.ox + dx, cy: this.oy + dy});
};
var up = function(){};
circ.drag(move,start,up);
<script>
Ok fine, it works and all functions are called properly!
BUT!
I want my move ,start ,up functions to be inside an object and not in the main page
SO
here's my next code
<script src="myobject.js"></script>
<script>
var paper = Raphael(100,100,500,500);
var myobj = new myobject("12","12","6");
<script>
Content of myobject.js :
function myobject(vx,vy,vr)
{
var x,y,r;
x=vx;y=vy;r=vr
paper.circle(x,y,r);
var start = function(){};
var move = function(dx,dy){};
var up = function(){};
this.drag(move,start,up); // error here this line crash
}
I cannot find how to use the drag function inside my object to make it draggable.
Well, that's it. I hope I've been clear and pardon me if there's anything wrong with the way I made this post but it is my first one!
Thanks to everyone that will try to help me!
Wilson
Inside myobject, this variable points to this object, and not to Raphael circle. As myobject does not have drag function, the code yields an error. To make it work, you must refer to Raphael object that has to be dragged, i.e.
function myobject(vx,vy,vr) {
...
this.circle = paper.circle(x,y,r);
...
this.circle.drag(move,start,up);
...
}
Fine, #Hubert OG was right but I also had to change the way I declared my function from
var start()=function
to
this.start() = function
WARNING: Fill your circle/forms because if you don't you have to click the fine border to move it around.

Why is 'this' not updating to refer to a new object?

I'm writing an online game which allows a user to progress from one puzzle to the next, and if the user makes mistakes, each puzzle has a start again button to allow the user to start just that puzzle from scratch. A simplified version of the code's structure is below:
function puzzle(generator) {
this.init = function() {
this.generator = generator;
...
this.addListeners();
}
//fires when the puzzle is solved
this.completed = function() {
window.theSequence.next();
}
this.empty = function() {
//get rid of all dom elements, all event listeners, and set all object properties to null;
}
this.addListeners = function() {
$('#startOver').click(function() {
window.thePuzzle.empty();
window.thePuzzle.init();
});
}
this.init();
}
function puzzleSequence(sequenceGenerator) {
this.init = function() {
//load the first puzzle
window.thePuzzle = new puzzle({generating json});
}
this.next = function() {
//destroy the last puzzle and create a new one
window.thePuzzle.empty();
window.thePuzzle = new puzzle({2nd generating json});
}
}
window.theSequence = new puzzleSequence({a sequence generator JSON});
The problem I have is that if the user has progressed to the second puzzle, if they click start over it loads the first puzzle rather than the second. After a bit of debugging I've worked out that 'this', when used in methods by the second puzzle, for some reason still holds a reference to the first puzzle, but 'window.thePuzzle' - which should be the same as this - correctly refers to the second puzzle.
Why is 'this' persisting in referrring to the first one?
Let me know if you need more code samples
$('#startOver').click(this.empty);
You've taken the empty method and detached it from this to pass as a plain unbound function to jQuery. When it gets called back, it will have no reference to the original value of this. In fact, when a function is called unbound, this will refer to window, so you'll be scribbling what you think are properties onto the globals.
JavaScript doesn't bind methods in the same way as other languages. See eg. this answer for an explanation of what it actually does. This confuses many people; personally I consider it one of JavaScript's worst flaws.
There is a very good (and clear) description of exactly how the this reference is treated in different contexts over at Quirksmode.

Categories

Resources