I am reading and trying to do this tutorial:
http://www.sitepoint.com/creating-a-simple-windows-8-game-with-javascript-input-and-sound/
Yesterday, I wrote in this forum with one error, and solved it, but today, I'm in the final one and getting another error.
My default.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CatapultGame</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- CatapultGame references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="js/CreateJS/easeljs-0.6.0.min.js"></script>
<script src="js/CreateJS/preloadjs-0.2.0.min.js"></script>
</head>
<body>
<canvas id="gameCanvas"></canvas>
</body>
</html>
and default.js file :
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
WinJS.strictProcessing();
var canvas, context, stage;
var bgImage, p1Image, p2Image, ammoImage, p1Lives, p2Lives, title, endGameImage;
var bgBitmap, p1Bitmap, p2Bitmap, ammoBitmap;
var preload;
// calculate display scale factor - original game assets assume 800x480
var SCALE_X = window.innerWidth / 800;
var SCALE_Y = window.innerHeight / 480;
var MARGIN = 25;
var GROUND_Y = 390 * SCALE_Y;
var LIVES_PER_PLAYER = 3;
var player1Lives = LIVES_PER_PLAYER;
var player2Lives = LIVES_PER_PLAYER;
var isShotFlying = false;
var playerTurn = 1;
var playerFire = false;
var shotVelocity;
var MAX_SHOT_POWER = 10;
var GRAVITY = 0.07;
var isAiming = false;
var aimPower = 1;
var aimStart, aimVector;
var FIRE_SOUND_FILE = "/sounds/CatapultFire.wav";
var HIT_SOUND_FILE = "/sounds/BoulderHit.wav";
var EXPLODE_SOUND_FILE = "/sounds/CatapultExplosion.wav";
var LOSE_SOUND_FILE = "/sounds/Lose.wav";
var AIM_SOUND_FILE = "/sounds/RopeStretch.wav";
var WIN_SOUND_FILE = "/sounds/Win.wav";
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
function initialize() {
canvas = document.getElementById("gameCanvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context = canvas.getContext("2d");
canvas.addEventListener("MSPointerUp", endAim, false);
canvas.addEventListener("MSPointerMove", adjustAim, false);
canvas.addEventListener("MSPointerDown", beginAim, false)
**var stage = new createjs.Stage(canvas);** <<========== HERE IS THE ERROR LINE !!!!
// use preloadJS to get sounds and images loaded before starting
preload = new createjs.PreloadJS();
preload.onComplete = prepareGame;
var manifest = [
{ id: "screenImage", src: "images/Backgrounds/gameplay_screen.png" },
{ id: "redImage", src: "images/Catapults/Red/redIdle/redIdle.png" },
{ id: "blueImage", src: "images/Catapults/Blue/blueIdle/blueIdle.png" },
{ id: "ammoImage", src: "images/Ammo/rock_ammo.png" },
{ id: "winImage", src: "images/Backgrounds/victory.png" },
{ id: "loseImage", src: "images/Backgrounds/defeat.png" },
{ id: "blueFire", src: "images/Catapults/Blue/blueFire/blueCatapultFire.png" },
{ id: "redFire", src: "images/Catapults/Red/redFire/redCatapultFire.png" },
{ id: "hitSound", src: HIT_SOUND_FILE },
{ id: "explodeSound", src: EXPLODE_SOUND_FILE },
{ id: "fireSound", src: FIRE_SOUND_FILE },
{ id: "loseSound", src: LOSE_SOUND_FILE },
{ id: "aimSound", src: AIM_SOUND_FILE },
{ id: "winSound", src: WIN_SOUND_FILE }
];
preload.loadManifest(manifest);
}
function prepareGame()
{
// draw Bg first, others appear on top
bgImage = preload.getResult("screenImage").result;
bgBitmap = new createjs.Bitmap(bgImage);
bgBitmap.scaleX = SCALE_X;
bgBitmap.scaleY = SCALE_Y;
stage.addChild(bgBitmap);
// draw p1 catapult
p1Image = preload.getResult("redImage").result;
p1Bitmap = new createjs.Bitmap(p1Image);
p1Bitmap.scaleX = SCALE_X;
p1Bitmap.scaleY = SCALE_Y;
p1Bitmap.x = MARGIN;
p1Bitmap.y = GROUND_Y - p1Image.height * SCALE_Y;
stage.addChild(p1Bitmap);
// draw p2 catapult and flip
p2Image = preload.getResult("blueImage").result;
p2Bitmap = new createjs.Bitmap(p2Image);
p2Bitmap.regX = p2Image.width;
p2Bitmap.scaleX = -SCALE_X; // flip from right edge
p2Bitmap.scaleY = SCALE_Y;
p2Bitmap.x = canvas.width - MARGIN - (p2Image.width * SCALE_X);
p2Bitmap.y = GROUND_Y - (p2Image.height * SCALE_Y);
stage.addChild(p2Bitmap);
// draw the boulder, and hide for the moment
ammoImage = preload.getResult("ammoImage").result;
ammoBitmap = new createjs.Bitmap(ammoImage);
ammoBitmap.scaleX = SCALE_X;
ammoBitmap.scaleY = SCALE_Y;
ammoBitmap.visible = false; // hide until fired
stage.addChild(ammoBitmap);
// player 1 lives
p1Lives = new createjs.Text("Lives Left : " + player1Lives, "20px sans-serif", "red");
p1Lives.scaleX = SCALE_X;
p1Lives.scaleY = SCALE_Y;
p1Lives.x = MARGIN;
p1Lives.y = MARGIN * SCALE_Y;
stage.addChild(p1Lives);
//player 2 lives
p2Lives = new createjs.Text("Lives Left : " + player2Lives, "20px sans-serif", "red");
p2Lives.scaleX = SCALE_X;
p2Lives.scaleY = SCALE_Y;
p2Lives.x = canvas.width - p2Lives.getMeasuredWidth() * SCALE_X - MARGIN;
p2Lives.y = MARGIN * SCALE_Y;
stage.addChild(p2Lives);
// game title
title = new createjs.Text("Catapult Wars", "30px sans-serif", "black");
title.scaleX = SCALE_X;
title.scaleY = SCALE_Y;
title.x = canvas.width / 2 - (title.getMeasuredWidth() * SCALE_X) / 2
title.y = 30 * SCALE_Y;
stage.addChild(title);
stage.update();
startGame();
}
function startGame()
{
Ticker.setInterval(window.requestAnimationFrame);
Ticker.addListener(gameLoop);
}
function gameLoop()
{
update();
draw();
}
function update() {
if (isShotFlying)
{
// shot in the air
ammoBitmap.x += shotVelocity.x;
ammoBitmap.y += shotVelocity.y;
shotVelocity.y += GRAVITY; //apply gravity to the y(height) values only, obviously
if (ammoBitmap.y + ammoBitmap.image.height >= GROUND_Y ||
ammoBitmap.x <= 0 ||
ammoBitmap.x + ammoBitmap.image.width >= canvas.width)
{
// missed
isShotFlying = false; //stop shot
ammoBitmap.visible = false;
playerTurn = playerTurn % 2 + 1; // invert player ( switch between 1 and 2)
}
else if (playerTurn == 1)
{
if (checkHit(p2Bitmap)) {
// Hit
p2Lives.text = "Lives Left : " + --player2Lives;
processHit();
}
}
else if (playerTurn == 2)
{
if (checkHit(p1Bitmap))
{
// Hit
p1Lives.text = "Lives Left : " + --player1Lives;
processHit();
}
}
}
// No current shot, should either player fire ?
else if (playerTurn == 1)
{
// does the player want to fire ?
if (playerFire)
{
playerFire = false;
ammoBitmap.x = p1Bitmap.x + (p1Bitmap.image.width * SCALE_X / 2);
ammoBitmap.y = p1Bitmap.y;
shotVelocity = aimVector;
fireShot();
}
}
else if (playerTurn == 2)
{
// AI automatically fires (randomly on it's turn)
ammoBitmap.x = p2Bitmap.x + (p2Bitmap.image.width * SCALE_X / 2);
ammoBitmap.y = p2Bitmap.y;
shotVelocity = new createjs.Point(
Math.random() * (-4 * SCALE_X) - 3,
Math.random() * (-3 * SCALE_Y) - 1);
fireShot();
}
}
// triggered by MSPointerDown event
function beginAim(event)
{
if (playerTurn == 1)
{
if (!isAiming)
{
aimStart = new createjs.Point(event.x, event.y);
isAiming = true;
}
}
}
// triggered by MSPointerMove event
function adjustAim(event)
{
if (isAiming)
{
var aimCurrent = new createjs.Point(event.x, event.y);
aimVector = calculateAim(aimStart, aimCurrent);
// TODO write text and/or show aiming arrow on screen
Debug.writeln("Aiming..." + aimVector.x + "/" + aimVector.y);
}
}
// triggered by MSPointerUp event
function endAim(event)
{
if (isAiming) {
isAiming = false;
var aimCurrent = new createjs.Point(event.x, event.y);
aimVector = calculateAim(aimStart, aimCurrent);
playerFire = true;
}
}
function calculateAim(start, end)
{
// this only works for player 1
var aim = new createjs.Point(
(end.x - start.x) / 80,
(end.y - start.y) / 80);
aim.x = Math.min(MAX_SHOT_POWER, aim.x); // cap velocity
aim.x = Math.max(0, aim.x); // fire forward only
aim.y = Math.max(-MAX_SHOT_POWER, aim.y);/// cap velocity
aim.y = Math.min(0, aim.y); // fire up only
return aim;
}
function checkHit(target)
{
// EaselJS hit test doesn't factor in scaling
// so use simple bounding box vs center of rock
// get centre of rock
var shotX = ammoBitmap.x + ammoBitmap.image.width / 2;
var shotY = ammoBitmap.y + ammoBitmap.image.height / 2;
// return wether center of rock is in rectangle bounding target player
return (((shotX > target.x) &&
(shotX <= target.x + (target.image.width * SCALE_X)))
&&
((shotY >= target.y) &&
(shotY <= target.y + (target.image.height * SCALE_Y))));
}
function fireShot()
{
playSound(FIRE_SOUND_FILE);
ammoBitmap.visible = true;
isShotFlying = true;
}
function processHit()
{
playSound(EXPLODE_SOUND_FILE);
isShotFlying = false; // stop shot
ammoBitmap.visible = false; // hide shot
playerTurn = playerTurn % 2 + 1; // change player
if ((player1Lives <= 0) || (player2Lives <= 0)) {
endGame();
}
}
function endGame()
{
Ticker.setPaused(true); // stop game loop
// show win/lose graphic
var endGameImage;
if (player1Lives <= 0)
{
playSound(LOSE_SOUND_FILE);
endGameImage = preload.getResult("loseImage").result;
}
else if (player2Lives <= 0)
{
endGameImage = preload.getResult("winImage").result;
playSound(WIN_SOUND_FILE);
}
var endGameBitmap = new createjs.Bitmap(endGameImage);
stage.addChild(endGameBitmap);
endGameBitmap.x = (canvas.width / 2) - (endGameImage.width * SCALE_X / 2);
endGameBitmap.y = (canvas.height / 2) - (endGameImage.height * SCALE_Y / 2);
endGameBitmap.scaleX = SCALE_X;
endGameBitmap.scaleY = SCALE_Y;
stage.update();
}
function draw() {
// EaselJS allows for easy updates
stage.update();
}
function playSound(path)
{
var sound = document.createElement("audio");
sound.src = path;
sound.autoplay = true;
}
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
document.addEventListener("DOMContentLoaded", initialize, false);
app.start();
})();
And there is the problem: when I'm trying to build this game, I'm getting error like this:
0x800a01bd - JavaScript runtime error: Object doesn't support this action
in the marked place in my code
Thanks for any help :)
Three problems, I report them from previous comments:
easeljs not present in the correct folder
mages/Catapults/Red/redFire/redCatapultFire.png missing
change var stage = new createjs.Stage(canvas); to stage = new createjs.Stage(canvas); you don't have to instantiate that variable as reported in the tutorial (http://www.sitepoint.com/creating-a-simple-windows-8-game-with-javascript-game-basics-createjseaseljs/)
And close this other related question (https://stackoverflow.com/a/16101960/975520), I think is solved by posting your solution as answer.
Related
I have a function that craeates divs with a circle.
Now they are all created and appear at the beginning of the page and go further in order.
Next, I need each circle to appear in a random place. I did this.
Now I need all of them to move randomly across the entire page, I have difficulties with this.
Here is an example of how everything works for one element that is already on the page.
https://jsfiddle.net/quej8wko/
But when I add this code, all my created circles don't move.
I get an error:
"message": "Uncaught TypeError: Cannot set properties of null (setting 'willChange')",
This is probably due to the fact that initially there are no circles on the page. How can I connect the code so that all created circles move?
//creating circles
var widthHeight = 40; // <-- circle width
var margin = 20; // <-- margin - is it necessary ?
var delta = widthHeight + margin;
function createDiv(id, color) {
let div = document.createElement('div');
var currentTop = 0;
var documentHeight = document.documentElement.clientHeight;
var documentWidth = document.documentElement.clientWidth;
div.setAttribute('class', id);
if (color === undefined) {
let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
div.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
}
else {
div.style.backgroundColor = color;
}
div.classList.add("circle");
div.classList.add("animation");
// Get the random positions minus the delta
currentTop = Math.floor(Math.random() * documentHeight) - delta;
currentLeft = Math.floor(Math.random() * documentWidth) - delta;
// Keep the positions between -20px and the current positions
var limitedTop = Math.max(margin * -1, currentTop);
var limitedLeft = Math.max(margin * -1, currentLeft);
div.style.top = limitedTop + "px";
div.style.left = limitedLeft + "px";
document.body.appendChild(div);
}
let i = 0;
const oneSecond = 1000;
setInterval(() => {
i += 1;
createDiv(`circle${i}`)
}, oneSecond);
//move circles
function RandomObjectMover(obj, container) {
this.$object = obj;
this.$container = container;
this.container_is_window = container === window;
this.pixels_per_second = 250;
this.current_position = { x: 0, y: 0 };
this.is_running = false;
}
// Set the speed of movement in Pixels per Second.
RandomObjectMover.prototype.setSpeed = function(pxPerSec) {
this.pixels_per_second = pxPerSec;
}
RandomObjectMover.prototype._getContainerDimensions = function() {
if (this.$container === window) {
return { 'height' : this.$container.innerHeight, 'width' : this.$container.innerWidth };
} else {
return { 'height' : this.$container.clientHeight, 'width' : this.$container.clientWidth };
}
}
RandomObjectMover.prototype._generateNewPosition = function() {
// Get container dimensions minus div size
var containerSize = this._getContainerDimensions();
var availableHeight = containerSize.height - this.$object.clientHeight;
var availableWidth = containerSize.width - this.$object.clientHeight;
// Pick a random place in the space
var y = Math.floor(Math.random() * availableHeight);
var x = Math.floor(Math.random() * availableWidth);
return { x: x, y: y };
}
RandomObjectMover.prototype._calcDelta = function(a, b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
var dist = Math.sqrt( dx*dx + dy*dy );
return dist;
}
RandomObjectMover.prototype._moveOnce = function() {
// Pick a new spot on the page
var next = this._generateNewPosition();
// How far do we have to move?
var delta = this._calcDelta(this.current_position, next);
// Speed of this transition, rounded to 2DP
var speed = Math.round((delta / this.pixels_per_second) * 100) / 100;
//console.log(this.current_position, next, delta, speed);
this.$object.style.transition='transform '+speed+'s linear';
this.$object.style.transform='translate3d('+next.x+'px, '+next.y+'px, 0)';
// Save this new position ready for the next call.
this.current_position = next;
};
RandomObjectMover.prototype.start = function() {
if (this.is_running) {
return;
}
// Make sure our object has the right css set
this.$object.willChange = 'transform';
this.$object.pointerEvents = 'auto';
this.boundEvent = this._moveOnce.bind(this)
// Bind callback to keep things moving
this.$object.addEventListener('transitionend', this.boundEvent);
// Start it moving
this._moveOnce();
this.is_running = true;
}
RandomObjectMover.prototype.stop = function() {
if (!this.is_running) {
return;
}
this.$object.removeEventListener('transitionend', this.boundEvent);
this.is_running = false;
}
// Init it
var x = new RandomObjectMover(document.querySelector(".circle"), window);
// Start it off
x.start();
.circle {
clip-path: circle(50%);
height: 40px;
width: 40px;
margin: 20px;
position: absolute;
}
I have modified the snippet which works as you expected.
There was a mistake where you were initializing and creating the object instance only once and none of the div elements that you created inside the setInterval function never got Instantiated.
I think you are just starting out with JavaScript with this sample project.
Below are few suggestions:
Learn to debug the code. You should be using dev tools by making use of debugger statement where it takes you to the source code to analyze the variable scope and stack during the runtime. console.log also helps in few situations.
I could see a lot of confusing naming convention (You have named the create div parameter as id but creating a div class using that id)
Try using ES6 features (class syntax is really good when writing OOP in JS although it's just a syntactic sugar for prototype)
//creating circles
var widthHeight = 40; // <-- circle width
var margin = 20; // <-- margin - is it necessary ?
var delta = widthHeight + margin;
function createAndInitializeDivObject(id, color) {
let div = document.createElement('div');
var currentTop = 0;
var documentHeight = document.documentElement.clientHeight;
var documentWidth = document.documentElement.clientWidth;
div.setAttribute('class', id);
if (color === undefined) {
let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
div.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
}
else {
div.style.backgroundColor = color;
}
div.classList.add("circle");
div.classList.add("animation");
// Get the random positions minus the delta
currentTop = Math.floor(Math.random() * documentHeight) - delta;
currentLeft = Math.floor(Math.random() * documentWidth) - delta;
// Keep the positions between -20px and the current positions
var limitedTop = Math.max(margin * -1, currentTop);
var limitedLeft = Math.max(margin * -1, currentLeft);
div.style.top = limitedTop + "px";
div.style.left = limitedLeft + "px";
document.body.appendChild(div);
var x = new RandomObjectMover(document.querySelector(`.${id}`), window);
x.start();
}
let i = 0;
const oneSecond = 1000;
setInterval(() => {
i += 1;
createAndInitializeDivObject(`circle${i}`)
}, oneSecond);
//move circles
function RandomObjectMover(obj, container) {
this.$object = obj;
this.$container = container;
this.container_is_window = container === window;
this.pixels_per_second = 250;
this.current_position = { x: 0, y: 0 };
this.is_running = false;
}
// Set the speed of movement in Pixels per Second.
RandomObjectMover.prototype.setSpeed = function(pxPerSec) {
this.pixels_per_second = pxPerSec;
}
RandomObjectMover.prototype._getContainerDimensions = function() {
if (this.$container === window) {
return { 'height' : this.$container.innerHeight, 'width' : this.$container.innerWidth };
} else {
return { 'height' : this.$container.clientHeight, 'width' : this.$container.clientWidth };
}
}
RandomObjectMover.prototype._generateNewPosition = function() {
// Get container dimensions minus div size
var containerSize = this._getContainerDimensions();
var availableHeight = containerSize.height - this.$object.clientHeight;
var availableWidth = containerSize.width - this.$object.clientHeight;
// Pick a random place in the space
var y = Math.floor(Math.random() * availableHeight);
var x = Math.floor(Math.random() * availableWidth);
return { x: x, y: y };
}
RandomObjectMover.prototype._calcDelta = function(a, b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
var dist = Math.sqrt( dx*dx + dy*dy );
return dist;
}
RandomObjectMover.prototype._moveOnce = function() {
// Pick a new spot on the page
var next = this._generateNewPosition();
// How far do we have to move?
var delta = this._calcDelta(this.current_position, next);
// Speed of this transition, rounded to 2DP
var speed = Math.round((delta / this.pixels_per_second) * 100) / 100;
//console.log(this.current_position, next, delta, speed);
this.$object.style.transition='transform '+speed+'s linear';
this.$object.style.transform='translate3d('+next.x+'px, '+next.y+'px, 0)';
// Save this new position ready for the next call.
this.current_position = next;
};
RandomObjectMover.prototype.start = function() {
if (this.is_running) {
return;
}
// Make sure our object has the right css set
this.$object.willChange = 'transform';
this.$object.pointerEvents = 'auto';
this.boundEvent = this._moveOnce.bind(this)
// Bind callback to keep things moving
this.$object.addEventListener('transitionend', this.boundEvent);
// Start it moving
this._moveOnce();
this.is_running = true;
}
RandomObjectMover.prototype.stop = function() {
if (!this.is_running) {
return;
}
this.$object.removeEventListener('transitionend', this.boundEvent);
this.is_running = false;
}
// Init it
var x = new RandomObjectMover(document.querySelector(".circle"), window);
// Start it off
x.start();
.circle {
width: 35px;
height: 35px;
border-radius: 35px;
background-color: #ffffff;
border: 3px solid purple;
position: absolute;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="circle"></div>
<script src="app.js"></script>
</body>
</html>
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 am trying to create a class which creates a Crafty entity with specific properties. So far, the functions within the class do not run because 'this' refers to the window object
$(document).ready(function () {
Crafty.init(window.innerWidth, window.innerHeight);
var player = new controller(37,38,39,40);
player.d.color("red").attr({
w: 50,
h: 50,
x: 0,
y: 0
});
// Jump Height = velocity ^ 2 / gravity * 2
// Terminal Velocity = push * (1 / viscosity)
var gravity = 1;
var viscosity = 0.5;
var frame = (1 / 20);
var distanceMultiplier = 10; //pixels per meter
var timeMultiplier = 20; //relative to actual time
var keystart = [];
var keyboard = [];
function controller (controls) {
this.d = Crafty.e();
this.d.addComponent("2D, Canvas, Color, Collision");
this.d.collision();
this.d.mass = 1;
this.d.a = {
extradistance : 0,
velocity : 0,
acceleration : 0,
force : 0,
resistance : 0
};
this.d.a.push = 0;
this.d.v = {
extradistance : 0,
velocity : 0,
acceleration : 0,
force : 0
};
this.d.jumping = true;
this.d.onHit("Collision", function () {
var a = this.d.hit("Collision");
if (a) {
for (var b in a) {
this.d.x = this.d.x - a[b].normal.x * a[b].overlap;
this.d.y = this.d.y - a[b].normal.y * a[b].overlap;
if (a[b].normal.y < -0.5) {
this.d.jumping = false;
}
if (Math.abs(a[b].normal.x) < 0.2) {
this.d.v.velocity = this.d.v.velocity * a[b].normal.y * 0.2;
}
if (Math.abs(a[b].normal.y) < 0.2) {
this.d.a.velocity = this.d.a.velocity * a[b].normal.x * 0.2;
}
}
return;
}
});
this.d.physics = function () {
if (keyboard[arguments[1]] && !this.jumping) {
this.v.velocity = 5;
this.jumping = true;
}
if (keyboard[arguments[1]] && this.jumping) {
var now = new Date();
if (now.getTime() - keystart[arguments[1]].getTime() < 500) {
this.v.velocity = 5;
}
}
if (keyboard[arguments[0]] && keyboard[arguments[2]]) {
this.a.velocity = 0;
} else {
if (keyboard[arguments[0]]) {
this.a.velocity = -3;
}
if (keyboard[arguments[2]]) {
this.a.velocity = 3;
}
}
if (keyboard[arguments[3]]) {
this.v.velocity = -5;
}
this.a.force = this.a.push - this.a.resistance;
this.a.acceleration = this.a.force / this.mass;
this.a.velocity = this.a.velocity + (this.a.acceleration * frame);
this.a.extradistance = (this.a.velocity * frame);
this.a.resistance = this.a.velocity * viscosity;
this.attr({
x: (this.x + (this.a.extradistance * distanceMultiplier))
});
this.v.force = gravity * this.mass;
this.v.acceleration = this.v.force / this.mass;
this.v.velocity = this.v.velocity - (this.v.acceleration * frame);
this.v.extradistance = (this.v.velocity * frame);
this.attr({
y: (this.y - (this.v.extradistance * distanceMultiplier))
});
setTimeout(this.physics, (frame * 1000) / timeMultiplier);
};
this.d.listen = function(){ document.body.addEventListener("keydown", function (code) {
var then = new Date();
if (!keyboard[code.keyCode] && !this.jumping && code.keyCode == arguments[1]) { //only if not yet pressed it will ignore everything until keyup
keyboard[code.keyCode] = true; //start movement
keystart[code.keyCode] = then; //set time
}
if (!keyboard[code.keyCode] && code.keyCode != arguments[1]) { //only if not yet pressed it will ignore everything until keyup
keyboard[code.keyCode] = true; //start movement
keystart[code.keyCode] = then; //set time
}
});
};
}
player.d.physics();
player.d.listen();
document.body.addEventListener("keyup", function (code) {
keyboard[code.keyCode] = false;
});
});
In trying to put the functions as prototypes of the class, I run into a problem.
Crafty.init(500,500);
function block () {
block.d = Crafty.e("2D, Color, Canvas");
block.d.color("red");
block.d.attr({x:0,y:0,h:50,w:50});
}
block.d.prototype.green = function() {
this.color("green");
}
var block1 = new block();
block1.d.color();
If an object is defined in the constructor, I cannot use it to add a prototype to.
Generally in Crafty, we favor composition. That is, you extend an entity by adding more components to it. You can have kind of a hierarchy by having one component automatically add others during init.
I haven't looked through all of your example code, because there's a lot! But consider the second block:
function block () {
block.d = Crafty.e("2D, Color, Canvas");
block.d.color("red");
block.d.attr({x:0,y:0,h:50,w:50});
}
block.d.prototype.green = function() {
this.color("green");
}
var block1 = new block();
block1.d.color();
You're trying to combine Crafty's way of doing things (an entity component system) with classes in a way that's not very idiomatic. Better to do this:
// Define a new component with Crafty.c(), rather than creating a class
Crafty.c("Block", {
// On init, add the correct components and setup the color and dimensions
init: function() {
this.requires("2D, Color, Canvas")
.color("red")
.attr({x:0,y:0,h:50,w:50});
},
// method for changing color
green: function() {
this.color("green");
}
});
// Create an entity with Crafty.e()
block1 = Crafty.e("Block");
// It's not easy being green!
block1.green();
I am working a building a simple Javascript Whack-a-mole game. I believe the issue is when by the time the "co-ordinates" for the mouse are read, the picture's X and Y values change.
When playing the game, you click on the picture, and the text that should come up when you successful click does not appear. This will not allow me to change to the picture to the "hit" picture, to let the players know they hit the object.
This is the code:
$(document).ready(function() {
document.body.onmousedown = function() {
return false;
} //so page is unselectable
//Canvas stuff
var canvas = $("#canvas")[0];
var ctx = canvas.getContext("2d");
var w = $("#canvas").width();
var h = $("#canvas").height();
var mx, my;
var player;
var mC;
var mR;
var smackSound = new Audio("audio/boing.wav");
var smackSound2 = new Audio("audio/boing2.wav");
var smackSound3 = new Audio("audio/boing3.wav");
var mel = new Image();
var melHit = new Image();
var melX;
var melY;
var melXref;
var melYref;
/////////////////////////////////
////////////////////////////////
//////// GAME INIT
/////// Runs this code right away, as soon as the page loads.
////// Use this code to get everything in order before the game starts
//////////////////////////////
/////////////////////////////
function init() {
//////////
///STATE VARIABLES
mel.src = "images/mel.jpg";
melHit.src = "images/melCrazy.jpg";
//////////////////////
///GAME ENGINE START
// This starts the game/program
// "paint is the piece of code that runs over and over again.
// "60" sets how fast things should go
if (typeof game_loop != "undefined") clearInterval(game_loop);
game_loop = setInterval(paint, 1000);
}
init();
function generate() {
var random;
random = Math.floor(Math.random() * 4);
while (random == 3) {
random = Math.floor(Math.random() * 4);
}
return random;
}
function posDisplay() {
ctx.fillStyle = "black"
ctx.fillText("Mouse Column: " + mC, 10, 10);
ctx.fillText("Mouse Row: " + mR, 10, 20);
}
///////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////// Main Game Engine
////////////////////////////////////////////////////
///////////////////////////////////////////////////
function paint() {
ctx.clearRect(0, 0, w, h);
melX = generate() * w / 3;
melY = generate() * h / 3;
//melXref = generate() / w / 3;
//melYref = generate() / h / 3;
//ctx.fillStyle = 'white';
posDisplay()
ctx.drawImage(mel, melX, melY, 200, 200);
if (melXref == mR && melYref == mC && clicker = true) {
ctx.fillStyle = "black";
ctx.fillText("It works!!!!!", 200, 200);
}
if (melX < w / 3 && clicker = true) { // First Column (Mel)
if (melY < h / 3) {
melXref = 1
melYref = 1
// clicker = true;
} else if (melY > h / 3 && melY < h / 1.5) {
melXref = 1
melYref = 2
// clicker = true;
} else if (melY > h / 1.5) {
melXref = 1
melYref = 3
// clicker = true;
}
} else if (melX > w / 3 && melX < w / 1.5 && clicker = true) { // Second Column (Mel)
if (melY < h / 3) {
melXref = 2
melYref = 1
// clicker = true;
} else if (melY > h / 3 && melY < h / 1.5) {
melXref = 2
melYref = 2
// clicker = true;
} else if (melY > h / 1.5) {
melXref = 2
melYref = 3
// clicker = true;
}
} else if (melX > w / 1.5 && clicker = true) { // Third Column (Mel)
if (melY < h / 3) {
melXref = 3
melYref = 1
// clicker = true;
} else if (melY > h / 3 && melY < h / 1.5) {
melXref = 3
melYref = 2
// clicker = true;
} else if (melY > h / 1.5) {
melXref = 3
melYref = 3
// clicker = true;
}
if (melXref == mR && melYref == mC) {
ctx.fillStyle = "black";
ctx.fillText("IT WORKS", 200, 200);
}
ctx.drawImage(mel, melX, melY, 200, 200);
if (melX == mx && melY == my) {
ctx.fillStyle = "black";
ctx.fillText("YESSSSSSSSS", 250, 250);
//ctx.drawImage(melHit,(generate()*200),(generate()*200),200,200);
}
} ////////////////////////////////////////////////////////////////////////////////END PAINT/ GAME ENGINE
}
////////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///// MOUSE LISTENER
//////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////
// Mouse Click
///////////////
canvas.addEventListener('click', function(evt) {
if (mx < w && my < h) {
clicker = true;
} else {
clicker = false;
}
if (clicker = true && mx < w && my < h) { // Randomizes the sound && only allows audio to be played if it is within the canvas
if (generate() == 1) {
smackSound.play();
} else if (generate() == 2) {
smackSound2.play();
} else if (generate() == 3) {
smackSound3.play();
}
}
}, false);
canvas.addEventListener('mouseout', function() {
pause = true;
}, false);
canvas.addEventListener('mouseover', function() {
pause = false;
}, false);
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
mx = mousePos.x;
my = mousePos.y;
if (mx < w / 3) { // First Column
if (my < h / 3) {
mC = 1
mR = 1
// clicker = true;
} else if (my > h / 3 && my < h / 1.5) {
mC = 1
mR = 2
//clicker = true;
} else if (my > h / 1.5) {
mC = 1
mR = 3
// clicker = true;
}
} else if (mx > w / 3 && mx < w / 1.5) { // Second Column
if (my < h / 3) {
mC = 2
mR = 1
// clicker = true;
} else if (my > h / 3 && my < h / 1.5) {
mC = 2
mR = 2
// clicker = true;
} else if (my > h / 1.5) {
mC = 2
mR = 3
// clicker = true;
}
} else if (mx > w / 1.5) { // Third Column
if (my < h / 3) {
mC = 3
mR = 1
// clicker = true;
} else if (my > h / 3 && my < h / 1.5) {
mC = 3
mR = 2
// clicker = true;
} else if (my > h / 1.5) {
mC = 3
mR = 3
// clicker = true;
}
}
}, false);
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
///////////////////////////////////
//////////////////////////////////
//////// KEY BOARD INPUT
////////////////////////////////
window.addEventListener('keydown', function(evt) {
var key = evt.keyCode;
//p 80
//r 82
//1 49
//2 50
//3 51
}, false);
})
This is a bit of a shot in the dark (and its too much to put in a comment), but from what I can tell, while you are recording the mouse position in the mousemove event, you are not doing so in the click event. I believe its not so much that the picture's X and Y have changed, it is probably that the last recorded mouse's X and Y have changed due to the mousemove event firing after the click.
A general solution (because it can be solved many different ways) might be to record the mouse's row and column in the click event, and then suppress any mouse position updates in the mousemove event if your clicker variable is true. So maybe something like the following:
canvas.addEventListener('mousemove', function(evt) {
if(!clicker){
// happily record the mouse position, because user hasn't clicked anything
In the paint method, you can check if clicker is true and do the text thing using the last known mouse position previously recorded in the click event, and then reset it back to false when you're done processing. Your paint method is fairly large, and clicker seems to be used throughout so I won't post a full blown code block in the interests of brevity, but I think you get the idea.
ALSO: I notice in your if statements, you're checking the clicker variable using && clicker = true. Notice the single equal sign? That's extremely bad! Instead of checking its value, you're assigned its value. Remember single equals is for assignment, double equals is for equivalence.
You can solve that error a couple of ways; the simplest is to simply make sure you change it to == instead, and anywhere else you might have made that error. Or, since its a boolean, you can simple do && clicker or && !clicker, depending on the condition.
Alternatively, from the looks of your logic, since every if and if else is dependent on whether clicker is true, you can get rid of the redundant checking in each condition and simply wrap the entire thing in oneif`, like so:
if(clicker){
if (melXref == mR && melYref == mC) {
ctx.fillStyle = "black";
ctx.fillText("It works!!!!!", 200, 200);
}
if (melX < w / 3) { // First Column (Mel)
... other conditions
}
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);