I'm an absolute beginner in coding in general. I was trying to adapt the code for controlling a car from this codepeninto my project structure.
Here is my code:
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import "./styles.css";
// TASK 2
//let timer = setInterval(myTimer, 1000); //isn't it supposed to show something?
//function myTimer(){
// let d = new Date();
// document.getElementById("demo").innerHTML = d.toLocaleTimeString();
//}
// TASK 3.1
//document.getElementById("app").innerHTML =`
//<h1>Hello Vanilla</h1>
//<div>
// We use the same configuration as Parcel to bundle this sandbox, you can find more
// info about Parcel
// here
//</div>`
// TASK 3.2
let scene, camera, renderer;
let geometry, material, cube;
let colour, intensity, light;
let ambientLight;
let orbit, controls;
let listener, sound, audioLoader;
let clock, delta, interval, elapsedTime, lastElapsedTime, deltaTime, tick;
let sceneHeight, sceneWidth;
let size, divisions;
let car, body, bonnet, wheels;
let leftPressed, rightPressed, upPressed, downPressed;
let startButton = document.getElementById("startButton");
startButton.addEventListener("click", init);
function init() {
//alert("We have initialised!");
let overlay = document.getElementById("overlay");
overlay.remove();
sceneWidth = window.innerWidth;
sceneHeight = window.innerHeight;
//create our clock and set interval at 30 fpx
clock = new THREE.Clock();
delta = 0;
interval = 1 / 30;
lastElapsedTime = 0;
//create the scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xdfdfdf);
//create fog
const fog = new THREE.Fog(0xc3ebcd, 15, 40);
scene.fog = fog;
//creating camera (fos,aspect,near,far)
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
camera.position.y = 5;
//skybox https://www.youtube.com/watch?v=PPwR7h5SnOE
let skyboxLoader = new THREE.CubeTextureLoader();
let skyboxTexture = skyboxLoader.load([
"./assets/skybox/xpos.png",
"./assets/skybox/xneg.png",
"./assets/skybox/ypos.png",
"./assets/skybox/yneg.png",
"./assets/skybox/zpos.png",
"./assets/skybox/zneg.png"
]);
scene.background = skyboxTexture;
//plane (ground) https://www.youtube.com/watch?v=PPwR7h5SnOE
let plane = new THREE.Mesh(
new THREE.PlaneGeometry(100, 100, 1, 1),
new THREE.MeshStandardMaterial({ color: 0xc3ebcd })
);
plane.castShadow = false;
plane.receiveShadow = true;
plane.rotation.x = -Math.PI / 2;
scene.add(plane);
//specify and adding renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//create orbit controls to interact with mouse
orbit = new OrbitControls(camera, renderer.domElement);
orbit.maxPolarAngle = 80 * (Math.PI / 180);
orbit.minDistance = 3;
orbit.maxDistance = 50;
orbit.enableDamping = true;
//CAR https://codepen.io/johndownie/pen/abjbLzy
car = new THREE.Group();
body = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({
color: "blue",
roughness: 0.5
})
);
body.position.y = 0.2;
body.castShadow = true;
bonnet = new THREE.Mesh(
new THREE.BoxGeometry(1, 0.5, 0.5),
new THREE.MeshStandardMaterial({
color: "blue",
roughness: 0.5
})
);
bonnet.position.z = -0.75;
bonnet.position.y = -0.25 + 0.2;
bonnet.castShadow = true;
wheels = [
{
name: "wheel1",
rotation: {
x: 0,
y: 0,
z: Math.PI * 0.5
},
position: {
x: 0.5 + 0.3 * 0.5,
y: -0.2,
z: 0.2
}
},
{
name: "wheel2",
rotation: {
x: 0,
y: 0,
z: -Math.PI * 0.5
},
position: {
x: -(0.5 + 0.3 * 0.5),
y: -0.2,
z: 0.2
}
},
{
name: "wheel3",
rotation: {
x: 0,
y: 0,
z: -Math.PI * 0.5
},
position: {
x: -(0.5 + 0.3 * 0.5),
y: -0.2,
z: -0.7
}
},
{
name: "wheel4",
rotation: {
x: 0,
y: 0,
z: Math.PI * 0.5
},
position: {
x: 0.5 + 0.3 * 0.5,
y: -0.2,
z: -0.7
}
}
];
for (let i = 0; i < wheels.length; i++) {
const wheel = new THREE.Mesh(
new THREE.CylinderGeometry(0.3, 0.3, 0.3, 10),
new THREE.MeshStandardMaterial({
color: 0x000000,
roughness: 0.5
})
);
wheel.rotation.set(
wheels[i].rotation.x,
wheels[i].rotation.y,
wheels[i].rotation.z
);
wheel.position.set(
wheels[i].position.x,
wheels[i].position.y,
wheels[i].position.z
);
wheel.name = wheels[i].name;
wheel.castShadow = true;
car.add(wheel);
}
car.add(body);
car.add(bonnet);
car.position.set(0, 0.5, 0);
scene.add(car);
//KEYBOARD SETUP
// Set up the key codes for the arrow keys
const LEFT_ARROW = 37;
const UP_ARROW = 38;
const RIGHT_ARROW = 39;
const DOWN_ARROW = 40;
// Set up a flag to track which keys are currently being pressed
let leftPressed = false;
let upPressed = false;
let rightPressed = false;
let downPressed = false;
// Listen for keydown events
document.addEventListener("keydown", function (event) {
// Check which key was pressed
switch (event.keyCode) {
case "LEFT_ARROW":
leftPressed = true;
break;
case UP_ARROW:
upPressed = true;
break;
case RIGHT_ARROW:
rightPressed = true;
break;
case DOWN_ARROW:
downPressed = true;
break;
default:
break;
}
});
// Listen for keyup events
document.addEventListener("keyup", function (event) {
// Check which key was released
switch (event.keyCode) {
case LEFT_ARROW:
leftPressed = false;
break;
case UP_ARROW:
upPressed = false;
break;
case RIGHT_ARROW:
rightPressed = false;
break;
case DOWN_ARROW:
downPressed = false;
break;
default:
break;
}
});
//First Person Camera https://www.youtube.com/watch?v=oqKzxPMLWxo
//controls = new FirstPersonControls(camera, renderer.domElement);
//controls.movementSpeed = 5;
//controls.lookSpeed = 0.8;
//fpsCamera = new FirstPersonCamera(this.camera, this.objects);
// lighting
colour = 0xffffff;
intensity = 1;
light = new THREE.DirectionalLight(colour, intensity);
light.position.set(100, 100, 100);
light.target.position.set(0, 0, 0);
light.castShadow = true;
scene.add(light);
ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// create a box to spin
//geometry = new THREE.BoxGeometry();
//material = new THREE.MeshNormalMaterial(); // Change this from normal to Phong in step 5
//cube = new THREE.Mesh(geometry, material);
//cube.position.set(0, 1, 0);
//cube.castShadow = true;
//cube.receiveShadow = true;
//scene.add(cube);
//SOUND (for single source and single listener)
listener = new THREE.AudioListener();
camera.add(listener);
sound = new THREE.PositionalAudio(listener);
audioLoader = new THREE.AudioLoader();
audioLoader.load("./sounds/CPC_Basic_Drone_Loop.mp3", function (buffer) {
sound.setBuffer(buffer);
sound.setRefDistance(5); //a double value representing the reference distance for reducing volume as the audio source moves further from the listener – i.e. the distance at which the volume reduction starts taking effect. This value is used by all distance models.
sound.setDirectionalCone(180, 230, 0.1);
sound.setLoop(true);
sound.setVolume(0.5);
sound.play();
});
//resize window
window.addEventListener("resize", onWindowResize, false);
//strech goal: add gridHelper
size = 20;
divisions = 20;
//let gridHelper = new THREE.GridHelper(size, divisions);
//scene.add(gridHelper);
play();
}
//stop animation
function stop() {
renderer.setAnimationLoop(null);
}
// simple render function
function render() {
//controls.update(clock.getDelta());
camera.position.z = car.position.z + 8;
camera.position.x = car.position.x + 8;
camera.lookAt(car.position);
renderer.render(scene, camera);
}
//start animation
function play() {
//callback — The function will be called every available frame. If null is passed it will stop any already ongoing animation
renderer.setAnimationLoop(() => {
update();
render();
});
}
//our update function
function update() {
//orbit.update();
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.04;
//cube.rotation.z -= 0.01;
tick = () => {
elapsedTime = clock.getElapsedTime();
deltaTime = elapsedTime - lastElapsedTime;
lastElapsedTime = elapsedTime;
// Update the car's rotation based on which arrow keys are being pressed
if (leftPressed) {
car.rotation.y += Math.PI / 45; // Rotate the car 4 degree clockwise
}
if (rightPressed) {
car.rotation.y -= Math.PI / 45; // Rotate the car 4 degree counterclockwise
}
const vector = new THREE.Vector3(); // create once and reuse it!
// Get the car's forward direction vector
const forward = car.getWorldDirection(vector);
// Set up the speed at which the car will move
const CAR_SPEED = deltaTime * 20;
// Update the car's position based on its forward direction and speed
if (upPressed) {
car.position.x -= forward.x * CAR_SPEED;
car.position.y -= forward.y * CAR_SPEED;
car.position.z -= forward.z * CAR_SPEED;
car.getObjectByName("wheel1").rotation.x -= CAR_SPEED;
car.getObjectByName("wheel2").rotation.x -= CAR_SPEED;
car.getObjectByName("wheel3").rotation.x -= CAR_SPEED;
car.getObjectByName("wheel4").rotation.x -= CAR_SPEED;
}
if (downPressed) {
car.position.x += forward.x * CAR_SPEED;
car.position.y += forward.y * CAR_SPEED;
car.position.z += forward.z * CAR_SPEED;
car.getObjectByName("wheel1").rotation.x += CAR_SPEED;
car.getObjectByName("wheel2").rotation.x += CAR_SPEED;
car.getObjectByName("wheel3").rotation.x += CAR_SPEED;
car.getObjectByName("wheel4").rotation.x += CAR_SPEED;
}
// Update controls
// controls.update();
// Call tick again on the next frame
window.requestAnimationFrame(tick);
};
tick();
}
function onWindowResize() {
sceneHeight = window.innerHeight;
sceneWidth = window.innerWidth;
renderer.setSize(sceneWidth, sceneHeight);
camera.aspect = sceneWidth / sceneHeight;
// Always call updateProjectionMatrix on camera change
//camera.updateProjectionMatrix();
}
Any help is much appreciated!!
However, not sure if I put the loops in the right function (whether update or renderer function). The car won't move.
Related
I am new to HTML and JS in general so I am currently lost on what I did wrong. I followed a tutorial by Chris Courses on Youtube (link: https://www.youtube.com/watch?v=4q2vvZn5aoo) until 1:27:13. The line of code was:
if (player.position.y > canvas.width){
console.log("you lose");
};
It worked perfectly for him, but I am not getting any console log nor any errors.
I tweaked a little bit of the code in order to fit the project that I need so I don't know if that's where I went wrong.
Here is my whole index.js:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext('2d');
//adjust canvas width/height to take full screen
canvas.width= 1680;
canvas.height= 945;
//img function to easily import images
function img(file){
const image = new Image();
image.src = 'sprites/' +file;
return image;
}
//declaring images
const platformImg = img('platform.png');
const bg1 = img('bg1.png');
const bg2 = img('bg2.png');
const bg3 = img('bg3.png');
const bg4 = img('bg4.png');
const bg5 = img('bg5.png');
//Declaring variables
const gravity = 0.5; //Global Gravity
var firstSplash = 1;
var lastSplash = 210;
var splash = new Image;
var timer = setInterval( function(){
if (firstSplash>lastSplash){
clearInterval( timer );
}else{
splash.src = "./sprites/Splash/splash("+( firstSplash++ )+").jpg";
}
}, 1000/30 ); //Draw at 30 frames per second
class Player {
constructor(){ // Player Position/Width/Height
this.position = {
x: 100,
y: 100
}
this.velocity = { // Player Gravity
x: 0,
y: 0
}
this.width = 30;
this.height = 30;
}
// Make Player Visible
draw(){
ctx.fillStyle = 'red';
ctx.fillRect(this.position.x, this.position.y, this.width, this.height)
}
update(){
this.draw();
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
// Gravity to Player
if (this.position.y + this.height + this.velocity.y <= canvas.height)
this.velocity.y += gravity;
}
}
class Platform {
constructor({x, y, image}) {
this.position = {
x,
y
}
this.width = 600
this.height = 180
this.image = image
}
draw() {
ctx.drawImage(this.image, this.position.x, this.position.y)
}
}
class Decoration {
constructor({x, y, image}) {
this.position = {
x,
y
}
this.width = 16800
this.height = 945
this.image = image
}
draw() {
ctx.drawImage(this.image, this.position.x, this.position.y)
}
}
//Declaring variables
let player = new Player();
let platforms = [new Platform({
x: -1,
y: 800,
image: platformImg
}),
new Platform({
x: 600 -1,
y: 800,
image: platformImg
})]
let decorations = [
new Decoration({
x:0,
y:0,
image: bg1
}),
bg2Deco = new Decoration({
x:0,
y:0,
image: bg2
}),
bg3Deco = new Decoration({
x:0,
y:0,
image: bg3
}),
bg4Deco = new Decoration({
x:0,
y:0,
image: bg4
}),
bg5Deco = new Decoration({
x:0,
y:0,
image: bg5
})
]
const keys = {
right:{
pressed: false
},
left:{
pressed: false
}
}
//Levels
let level = 1
let levels = {
1: {
init: () => {
player = new Player();
platforms = [new Platform({
x: -1,
y: 800,
image: platformImg
}),
Platform({
x: 600 -1,
y: 800,
image: platformImg
})]
decorations = [
new Decoration({
x:0,
y:0,
image: bg1
}),
bg2Deco = new Decoration({
x:0,
y:0,
image: bg2
}),
bg3Deco = new Decoration({
x:0,
y:0,
image: bg3
}),
bg4Deco = new Decoration({
x:0,
y:0,
image: bg4
}),
bg5Deco = new Decoration({
x:0,
y:0,
image: bg5
})
]
}
}
}
// function drawSplash(){
// splash.onload = function(){
// ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
// ctx.drawImage(splash, 0, 0, ctx.canvas.width, ctx.canvas.height);
// };
// }
function gameStart(){
ctx.fillStyle = 'black'
ctx.fillRect(0,0,canvas.width, canvas.height)
document.getElementById("btnStart").remove();
player.draw();
animate();
}
function animate(){ // Animate
requestAnimationFrame(animate);
ctx.fillStyle = 'white';
ctx.fillRect(0,0,canvas.width, canvas.height)
decorations.forEach(Decoration =>{
Decoration.draw();
});
platforms.forEach(platform =>{
platform.draw();
});
player.update();
// Hold left/right for moving player
if (keys.right.pressed && player.position.x < 400){
player.velocity.x = 5
} else if (keys.left.pressed && player.position.x > 100) {
player.velocity.x = -5
} else {
player.velocity.x = 0
if (keys.right.pressed){
platforms.forEach(platform =>{
platform.position.x -=5
});
bg2Deco.position.x -= 3;
bg3Deco.position.x -= 4;
bg4Deco.position.x -= 5;
bg5Deco.position.x -= 6;
} else if (keys.left.pressed){
platforms.forEach(platform =>{
platform.position.x +=5
});
bg2Deco.position.x += 3;
bg3Deco.position.x += 4;
bg4Deco.position.x += 5;
bg5Deco.position.x += 6;
}
}
// Platform detection for player
platforms.forEach(platform =>{
if (player.position.y + player.height <= platform.position.y && player.position.y + player.height + player.velocity.y >= platform.position.y && player.position.x + player.width >= platform.position.x && player.position.x <= platform.position.x + platform.width) {
player.velocity.y = 0;
}
});
}
//lose condition
if (player.position.y > canvas.width){
console.log("you lose");
};
document.body.addEventListener('keydown', keyDown);
document.body.addEventListener('keyup', keyUp);
function keyDown(event){
if(event.code == "ArrowUp"){
if(event.repeat){return}
else player.velocity.y -= 10;
}
if(event.code == "ArrowLeft"){
keys.left.pressed = true;
}
if(event.code == "ArrowRight"){
keys.right.pressed = true;
}
}
function keyUp(event){
if(event.code == "ArrowUp"){
player.velocity.y -= 10;
}
if(event.code == "ArrowLeft"){
keys.left.pressed = false;
}
if(event.code == "ArrowRight"){
keys.right.pressed = false;
}
}
player.draw();
animate();
//drawSplash();
I feel like I'm being an idiot and missing something trivial. Any help is appreciated! Thank you!
It was confirmed that the function did not work properly.
The "you loose" if statement was outside.
Check yours animate function indent plz.
function animate() { // Animate
requestAnimationFrame(animate);
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height)
decorations.forEach(Decoration => {
Decoration.draw();
});
platforms.forEach(platform => {
platform.draw();
});
player.update();
// Hold left/right for moving player
if (keys.right.pressed && player.position.x < 400) {
player.velocity.x = 5
} else if (keys.left.pressed && player.position.x > 100) {
player.velocity.x = -5
} else {
player.velocity.x = 0
if (keys.right.pressed) {
platforms.forEach(platform => {
platform.position.x -= 5
});
bg2Deco.position.x -= 3;
bg3Deco.position.x -= 4;
bg4Deco.position.x -= 5;
bg5Deco.position.x -= 6;
} else if (keys.left.pressed) {
platforms.forEach(platform => {
platform.position.x += 5
});
bg2Deco.position.x += 3;
bg3Deco.position.x += 4;
bg4Deco.position.x += 5;
bg5Deco.position.x += 6;
}
}
// Platform detection for player
platforms.forEach(platform => {
if (player.position.y + player.height <= platform.position.y && player.position.y + player.height + player.velocity.y >= platform.position.y && player.position.x + player.width >= platform.position.x && player.position.x <= platform.position.x + platform.width) {
player.velocity.y = 0;
}
});
//lose condition
// Check here.
if (player.position.y > canvas.width) {
console.log("you lose");
}
}
I am using three.min.js and works beautifully but the model is spinning endlessly. How to stop it and allow user to spin manually? And the spinning is off centered also, is there away to resolve this?
<script>
if (!Detector.webgl) Detector.addGetWebGLMessage();
var container, stats;
var camera, cameraTarget, scene, renderer;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 15);
camera.position.set(3, 0.15, 3);
cameraTarget = new THREE.Vector3(0, -0.25, 0);
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x72645b, 2, 15);
// Ground
var plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(40, 40),
new THREE.MeshPhongMaterial({ color: 0x999999, specular: 0x101010 })
);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
scene.add(plane);
plane.receiveShadow = true;
var loader = new THREE.STLLoader();
// Binary files
var material = new THREE.MeshPhongMaterial({ color: 0xAAAAAA, specular: 0x111111, shininess: 200 });
loader.load('/productimages/mannequin.stl', function (geometry) {
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, -0.37, -0.6);
mesh.rotation.set(-Math.PI / 2, 0, 0);
mesh.scale.set(0.2, 0.2, 0.2);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
});
// Lights
scene.add(new THREE.AmbientLight(0x777777));
addShadowedLight(1, 1, 1, 0xffffff, 1.35);
addShadowedLight(0.5, 1, -1, 0xffaa00, 1);
// renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor(scene.fog.color);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapCullFace = THREE.CullFaceBack;
container.appendChild(renderer.domElement);
// stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.domElement);
//
window.addEventListener('resize', onWindowResize, false);
}
function addShadowedLight(x, y, z, color, intensity) {
var directionalLight = new THREE.DirectionalLight(color, intensity);
directionalLight.position.set(x, y, z)
scene.add(directionalLight);
directionalLight.castShadow = true;
// directionalLight.shadowCameraVisible = true;
var d = 1;
directionalLight.shadowCameraLeft = -d;
directionalLight.shadowCameraRight = d;
directionalLight.shadowCameraTop = d;
directionalLight.shadowCameraBottom = -d;
directionalLight.shadowCameraNear = 1;
directionalLight.shadowCameraFar = 4;
directionalLight.shadowMapWidth = 1024;
directionalLight.shadowMapHeight = 1024;
directionalLight.shadowBias = -0.005;
directionalLight.shadowDarkness = 0.15;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
var timer = Date.now() * 0.0005;
camera.position.x = Math.cos(timer) * 3;
camera.position.z = Math.sin(timer) * 3;
camera.lookAt(cameraTarget);
renderer.render(scene, camera);
}
</script>
to stop it from spinning just remove the:
var timer = Date.now() * 0.0005;
camera.position.x = Math.cos(timer) * 3;
camera.position.z = Math.sin(timer) * 3;
from the render function or make a function to enable this part on click.
"Hero" needs to get flipped horizontally (coordinate or new sprite, doesn't matter) on left/right keyDown. Including draw and keyDown sections. Where exactly would coordinate offset, or new sprite go, when left/right keyDown? Thanks in advance.
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "hero.png";
var owlReady = false;
var owlImage = new Image();
owlImage.onload = function () {
owlReady = true;
};
owlImage.src = "owl.png";
var hero = {
speed: 256,
x: 0,
y: 0
};
var owl = {
x: 0,
y: 0
};
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
var reset = function () {
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
var update = function (modifier) {
if (38 in keysDown) {
hero.y -= hero.speed * modifier;
}
if (40 in keysDown) {
hero.y += hero.speed * modifier;
}
if (37 in keysDown) {
hero.x -=hero.speed * modifier;
}
if (39 in keysDown) {
hero.x +=hero.speed * modifier;
}
//collision
if (
hero.x <= (owl.x + 35)
&& owl.x <= (hero.x + 35)
&& hero.y <= (owl.y + 35)
&& owl.y <= (hero.y + 35)
) {
++owlsCaught;
reset();
}
};
//DRAW
var render = function () {
if (bgReady) {
context.drawImage(bgImage, 0, 0);
}
if (heroReady) {
context.drawImage(heroImage, hero.x, hero.y);
}
if (owlReady) {
context.drawImage(owlImage, owl.x, owl.y);
}
//game loop
var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
requestAnimationFrame(main);
};
//play
var then = Date.now();
reset();
main();
</script>
Just use the scale() method with negative one to flip the coordinate system. You also need to think "negative" in the sense that you move the character in negative direction with the effect of actually going in positive direction after doing this.
Example:
ctx.scale(-1, 1); // flip hor.
ctx.drawImage(img, -x - img.width, 0); // use neg. position -image width
ctx.scale(-1, 1); // flip back to normal
FIDDLE
You could of course prep the character by creating an off-screen canvas the size of the image, flip the axis, draw the image flipped and use the off-screen canvas as an image source.
Update (for the new code shown)
You could use a flag to know which direction the hero is currently facing:
var flipped = false;
if (37 in keysDown) {
hero.x -=hero.speed * modifier;
flipped = true;
}
if (39 in keysDown) {
hero.x +=hero.speed * modifier;
flipped = false;
}
Then in the render function:
if (heroReady) {
if (flipped) {
context.scale(-1, 1);
context.drawImage(heroImage, -hero.x - heroImage.width, hero.y);
context.scale(-1, 1);
}
else {
context.drawImage(heroImage, hero.x, hero.y);
}
}
I have a kineticjs canvas with image upload and text input, both functions are working fine but I can't get the image resize anchors to show... I need to get the image resize anchors to show "onClick" of the image.
any help is much appreciated :)
thanks in advance.
here is the js
var stage = new Kinetic.Stage({
container: 'container',
width: 375,
height: 200
});
var layer = new Kinetic.Layer();
//image loader
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
layer.add(new Kinetic.Image({
x: 100,
y: 50,
image: img,
width: 200,
height: 130,
draggable: true
}));
text.moveToTop();
stage.draw();
};
console.log(event);
img.src = event.target.result;
};
reader.readAsDataURL(e.target.files[0]);
}
// parameters
var resizerRadius = 3;
var rr = resizerRadius * resizerRadius;
// constant
var pi2 = Math.PI * 2;
function draw(img, withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
var view = img.view;
ctx.drawImage(img, 0, 0, img.width, img.height, view.left, view.top, view.width, view.height);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(view.left, view.top);
drawDragAnchor(view.left + view.width, view.top);
drawDragAnchor(view.left + view.width, view.top + view.height);
drawDragAnchor(view.left, view.top + view.height);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.rect(view.left, view.top, view.width, view.height);
ctx.stroke();
}
drawText();
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function drawText(){
var x = 40,
y = 100;
ctx.font = "bold 20px sans-serif";
ctx.fillStyle = "black";
ctx.fillText($("#textBox").val(), x, y);
}
// -------------------------------------------
// - Hit Testing -
// -------------------------------------------
// return 0,1,2, or 3 if (x,y) hits the respective anchor
// of the given view.
// return -1 if no anchor hit.
function anchorHitTest(view, x, y) {
var dx, dy;
x -= view.left;
y -= view.top;
// top-left
dx = x;
dy = y;
if (dx * dx + dy * dy <= rr) return (0);
// top-right
dx = x - view.width;
dy = y;
if (dx * dx + dy * dy <= rr) return (1);
// bottom-right
dx = x - view.width;
dy = y - view.height;
if (dx * dx + dy * dy <= rr) return (2);
// bottom-left
dx = x;
dy = y - view.height;
if (dx * dx + dy * dy <= rr) return (3);
return (-1);
}
// return true if (x,y) lies within the view
function hitImage(view, x, y) {
x -= view.left;
y -= view.top;
return (x > 0 && x < view.width && y > 0 && y < view.height);
}
// -------------------------------------------
// - Mouse -
// -------------------------------------------
var mousePos = {
x: 0,
y: 0
};
var draggingImage = false;
var startX, startY;
var isDown = false;
var currentImg = null;
var draggingResizer;
function updateMousePos(e) {
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
updateMousePos = function (e) {
mousePos.x = parseInt(e.clientX - offsetX);
mousePos.y = parseInt(e.clientY - offsetY);
};
return updateMousePos(e);
}
function handleMouseDown(e) {
updateMousePos(e);
// here you could make a loop to see which image / anchor was clicked
draggingResizer = anchorHitTest(img.view, mousePos.x, mousePos.y);
draggingImage = draggingResizer < 0 && hitImage(img.view, mousePos.x, mousePos.y);
//
if (draggingResizer<0 && !draggingImage) return;
startX = mousePos.x;
startY = mousePos.y;
currentImg = img;
}
function handleMouseUp(e) {
if (!currentImg) return;
draggingResizer = -1;
draggingImage = false;
draw(currentImg, true, false);
currentImg = null;
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (!currentImg) return;
updateMousePos(e);
var view = currentImg.view;
if (draggingResizer > -1) {
var oldView = {
left: view.left,
top: view.top,
width: view.width,
height: view.height
};
// resize the image
switch (draggingResizer) {
case 0:
cl('ttoo');
//top-left
view.left = mousePos.x;
view.top = mousePos.y;
view.width = oldView.left + oldView.width - mousePos.x;
view.height = oldView.top + oldView.height - mousePos.y;
break;
case 1:
//top-right
// view.left unchanged
view.top = mousePos.y;
view.width = mousePos.x - oldView.left;
view.height = oldView.top + oldView.height - mousePos.y;
break;
case 2:
//bottom-right
view.width = mousePos.x - oldView.left;
view.height = mousePos.y - oldView.top;
break;
case 3:
//bottom-left
view.left = mousePos.x;
view.width = oldView.left + oldView.width - mousePos.x;
view.height = mousePos.y - (oldView.top);
break;
}
if (view.width < 25) view.width = 25;
if (view.height < 25) view.height = 25;
// redraw the image with resizing anchors
draw(currentImg, true, true);
} else if (draggingImage) {
imageClick = false;
// move the image by the amount of the latest drag
var dx = mousePos.x - startX;
var dy = mousePos.y - startY;
view.left += dx;
view.top += dy;
// reset the startXY for next time
startX = mousePos.x;
startY = mousePos.y;
// redraw the image with border
draw(currentImg, false, true);
}
}
var text = new Kinetic.Text({
x: 20,
y: 30,
text: '',
fontSize: '30',
fontFamily: 'Calibri',
fill: 'black',
draggable: true
});
stage.add(layer);
layer.add(text);
document.getElementById("textBox").addEventListener("keyup", function () {
text.setText(this.value);
layer.draw();
}, true);
document.getElementById("textSize").addEventListener("change", function () {
var size = this.value;
text.fontSize(size);
layer.draw();
}, true);
document.getElementById("fontFamily").addEventListener("change", function () {
var font = this.value;
text.fontFamily(font);
layer.draw();
}, true);
document.getElementById("fontStyle").addEventListener("change", function () {
var style = this.value;
text.fontStyle(style);
layer.draw();
}, true);
document.getElementById("fill").addEventListener("change", function () {
var colour = this.value;
text.fill(colour);
layer.draw();
}, true);
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
// utility
function cl() {
console.log.apply(console, arguments);
}
can provide jsFiddle if needed :)
You're trying to mix KineticJS with html canvas drawing commands.
That combination doesn't work because KineticJS does its magic by taking over the canvas--leaving no ability to call native canvas commands like context.beginPath.
// these 2 don't play together
... new Kinetic.Image ...
... ctx.beginPath ...
Anyway, Here's the answer to your question (in case you choose KineticJS for your project)
Kinetic.Image can be asked to execute a function when the image is clicked like this:
var image=new Kinetic.Image({
x: 100,
y: 50,
image: img,
width: 200,
height: 130,
draggable: true
}));
image.on("click",function(){
// The image was clicked
// Show your anchors now
});
layer.add(image);
[ Addition: Example of Kinetic.Image resizing ]
I don't like the overhead and complexity of maintaining anchors to resize Kinetic.Images.
Here's an example that lets you drag on the right side of the image to scale it proportionally:
http://jsfiddle.net/m1erickson/p8bpC/
You could modify this code to add cosmetic resizing grabbers (the grabbers are not necessary, but if you prefer the "anchor" look, you can add them).
You can refer to this question, the answers are guided and constructive, and contain a jsfiddle with the exact same behavior that you need.
Kinetic JS - how do you hide all the anchors for a given group ID
I'm having trouble keeping one object on my canvas. The initially drawn box rendered it in the correct position, but it disappears when I drag it:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
eraseAllButton = document.getElementById('eraseAllButton'),
strokeStyleSelect = document.getElementById('strokeStyleSelect'),
guidewireCheckbox = document.getElementById('guidewireCheckbox'),
drawingSurfaceImageData,
mousedown = {},
rubberbandRect = {},
dragging = false,
guidewires = guidewireCheckbox.checked,
w = 90, h = 90;
count = 0;
boxesXCo = 0;
boxesYCo = 0;
i = 0;
// Functions..........................................................
function drawGrid(color, stepx, stepy) {
context.save()
context.strokeStyle = color;
context.lineWidth = 0.5;
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
for (var i = stepx + 0.5; i < context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i < context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
context.restore();
}
function windowToCanvas(x, y) {
var bbox = canvas.getBoundingClientRect();
return { x: x - bbox.left * (canvas.width / bbox.width),
y: y - bbox.top * (canvas.height / bbox.height) };
}
// Save and restore drawing surface...................................
function saveDrawingSurface() {
drawingSurfaceImageData = context.getImageData(0, 0,
canvas.width,
canvas.height);
}
function restoreDrawingSurface() {
context.putImageData(drawingSurfaceImageData, 0, 0);
}
function drawRubberbandShape(loc) {
context.beginPath();
context.moveTo(mousedown.x, mousedown.y);
//context.lineTo(loc.x, loc.y);
context.stroke();
}
function updateRubberband(loc) {
//updateRubberbandRectangle(loc);
context.restore();
drawRubberbandShape(loc);
}
// Guidewires.........................................................
function drawHorizontalLine (y) {
context.beginPath();
context.moveTo(0,y+0.5);
context.lineTo(context.canvas.width,y+0.5);
context.stroke();
}
function drawVerticalLine (x) {
context.beginPath();
context.moveTo(x+0.5,0);
context.lineTo(x+0.5,context.canvas.height);
context.stroke();
}
function drawGuidewires(x, y) {
context.save();
context.strokeStyle = 'rgba(0,0,230,0.4)';
context.lineWidth = 0.5;
drawVerticalLine(x);
drawHorizontalLine(y);
context.restore();
}
// Canvas event handlers..............................................
canvas.onmousedown = function (e) {
var loc = windowToCanvas(e.clientX, e.clientY);
e.preventDefault(); // prevent cursor change
context.restore();
saveDrawingSurface();
mousedown.x = loc.x;
mousedown.y = loc.y;
dragging = true;
if (i ==0)
i++;
else if(((mousedown.x<=(boxesXCo+w)&&(mousedown.x>=boxesXCo))&&
((mousedown.y<=(boxesYCo+h)&&(mousedown.y>=boxesYCo)))))
i--;
};
canvas.onmousemove = function (e) {
var loc;
if (dragging) {
e.preventDefault(); // prevent selections
loc = windowToCanvas(e.clientX, e.clientY);
restoreDrawingSurface();
//updateRubberband(loc);
if(guidewires) {
drawGuidewires(loc.x, loc.y);
}
}
if(((mousedown.x<=(boxesXCo+w)&&(mousedown.x>=boxesXCo))&&
((mousedown.y<=(boxesYCo+h)&&(mousedown.y>=boxesYCo))))
&& (dragging)&&(i == 1 )){
context.restore();
restoreDrawingSurface();
context.fillStyle = strokeStyleSelect.value;
context.fillRect(e.clientX,e.clientY,w,h);
};
//Trying to implement moving shapes but need to store values of drawn objs
};
canvas.onmouseup = function (e) {
loc = windowToCanvas(e.clientX, e.clientY);
restoreDrawingSurface();
updateRubberband(loc);
dragging = false;
if(i == 0);
else {
saveDrawingSurface();
restoreDrawingSurface();
context.fillRect(e.clientX,e.clientY, w, h);
boxesXCo = e.clientX;
boxesYCo = e.clientY;
context.restore();
i++;}
/*else if(i == 1)
{
context.restore();
}*/
//context.fillRect(mousedown.x,mousedown.y,w,h,"FF0982");
};
// Controls event handlers.......................................
eraseAllButton.onclick = function (e) {
context.clearRect(0, 0, canvas.width, canvas.height);
drawGrid('lightgray', 10, 10);
saveDrawingSurface();
count =0;
context.restore();
};
strokeStyleSelect.onchange = function (e) {
context.strokeStyle = strokeStyleSelect.value;
context.fillStyle = strokeStyleSelect.value;
};
guidewireCheckbox.onchange = function (e) {
guidewires = guidewireCheckbox.checked;
};
// Initialization................................................
context.strokeStyle = strokeStyleSelect.value;
context.fillStyle = strokeStyleSelect.value;
drawGrid('lightgray', 10, 10);
//context.fillRect(mousedown.x,mousedown.y,(mousedown.x+50),(mousedown.x+50),"FF0982");
//context.drawRect(mousedown.x-50,mousedown.y-50,mousedown.x+50,mousedown.y+50);
thanx again
Rather than drawing to canvas on each mouse movement, use window.requestFrameAnimation to draw constantly.
At a guess, I'd assume either the browser rendering is interfering or the coordinates are out but I can't run your code to make sure.
I've written some pseudo code that shows what I do for rendering things. You'll need to implement this for yourself, it won't run out of the box, it's just intended as a guide.
var Box = function() {
};
Box.prototype = {
x: 0,
y: 0,
draw: function (canvas) {
// draw the item on the canvas
}
};
var box = new Box();
window.requestAnimationFrame(function() {
box.draw(canvas);
window.requestAnimationFrame();
});
canvas.onmousemove = function(e) {
if (dragging) {
box.x = e.clientX;
box.y = e.clientY;
}
}