Couldn't you put a sensor that triggers if the ball contacts from the outside and creates a gate?
Perhaps add two rectangles vis(false) at the sides and addPhysics(false)
new Rectangle(50,H).vis(false).reg(CENTER).loc(maze.x-25,H/2).addPhysics(false);
new Rectangle(50,H).vis(false).reg(CENTER).loc(maze.x+maze.width+25,H/2).addPhysics(false);
For adding another picture...
-
Use let ctx and let maze - rather than const. Or var is fine too.
-
when you want a new maze set maze dispose() the old maze and set maze to the new pic and cache it. And then set the ctx again to the new maze cacheCanavs.
I put the target rectangle inside the maze.
I will try to do what you said. I am new to physics so I don't know much. Thank you for your suggestion.
I usually use a container. To change it, I delete the container with removeAllChildren() and add a new one. But as you said, the container does not work for objects that use physics. For this reason, I only added the labyrinth images to the general container. and wrote the code below. I solved the renewal process. I solved my problem for now. Thank you for your help. But I need to study physics more and learn more.
function newCreate(){
generalCont.removeAllChildren()
maze = new Pic("maze4.png").pos(0,50,CENTER,CENTER,generalCont).cache();
ball.dynamic = true;
ball.vis(true);
emitter.loc(ball).spurt(20);
ctx = maze.cacheCanvas.getContext('2d');
num = 20; // test a 10x10 grid around the ball
space = 1; // the spacing of the points on the grid
radius = 1; // the radius of a wall placed at a point
walls = []; // an array to keep track of the active walls
}
Good. You probably would not need to recreate the ball, emitter, target, walls, etc. Just really the pic and the context.
Dan can you make it a zapp to share? thankZ
Note in this one, we have simplified the getting pixel color because we added a getColorAt(x,y) method to the bitmap.
But the new with straight lines
We already did a maze with the straight lines - our 3D one. @Ferudun is working on ones in 2D - let's let him do it. You can work on it yourself too.
new Label("RING MAZE", 40, "Fascinate Inline", pink)
.pos(0, 0, CENTER, TOP)
.noMouse();
const button = new Button({label: "BAŞLA", corner: 6}).sca(1).pos(10, 10, RIGHT, BOTTOM).tap(() => {
button.removeFrom();
timeout(1, () => {
ball.dynamic = true;
});
});
STYLE = {once: true, italic: true, bold: true};
// MAZE
// we can load in ANY picture of a maze as long as the walls are different than the backing
// we could even load two pictures... a hidden one to represent the walls and a visual more complex one
// we then use physics to apply a force to the ball to follow the mouse
// and we make physic walls dynamically around the ball's position
// the walls are placed only on the non-background color
// the walls are removed as the ball leaves the area and new ones are made
// thanks https://www.mazegenerator.net/
// note: we made a vertical maze to start at the top and bottom
// then rotated the image to start at the sides
var generalCont=new Container().center()
var maze = new Pic("maze1.png").pos(0,50,CENTER,CENTER,generalCont).cache();
// cache the image so we have a second canvas to use later
// this allows us to get the color of the pixel under the ball
// without getting the color of the ball ;-)
// new Label("START",25,null,white).pos(90,-20,LEFT,CENTER,holder);
// new Label("END",25,null,white).pos(60,-20,RIGHT,CENTER,holder);
//new Rectangle(W,H,new GradientColor([blue,green,orange,yellow])).addTo(holder).ble("darken");
// create a Physics instance to handle making the ball bounce off walls
// we will make walls dynamically only in the area of the ball
// that way we don't make thousands of walls that we don't need
// use the default outer walls and set gravity to 0
const physics = new Physics(0);
// physics.debug()
const ball = new Circle(12, red).pos(-480,410,CENTER).addPhysics({dynamic:false, contract:3});
ball.startX = ball.x;
ball.startY = ball.y;
// add an optional little finder
new Circle(30, black.toAlpha(.3)).center(ball, 0).wiggle("scale", 1, .1, .2, .7, 1.5);
const end = new Rectangle(20, 40, red).pos(480,330,CENTER,BOTTOM,maze).addTo(S)
// create a Ticker to constantly apply a force to the ball
// and make the walls near the ball
// the factor is for the force
// balance the speed with a tendency to go through walls if too fast
const emitter = new Emitter({
startPaused: true,
obj: new Circle(ball.radius * 1.3, clear, purple, 3),
animation: {scale: {min: .5, max: 1.5}},
force: {min: .5, max: 1.5},
gravity: 0
})
const factor = .005; // force is incremental in time (make small)
const max = .5; // limit the mouse distance (which limits force)
Ticker.add(() => {
// make the walls
makeWalls();
// apply a force towards the mouse
// do not use stage.mouseX and stage.mouseY
// as they do not catch touch location
// use any mouse event's mouseX and mouseY instead
// we did that and stored the values in mouseX and mouseY
let dX = constrain((F.mouseX - ball.x) * factor, -max, max);
let dY = constrain((F.mouseY - ball.y) * factor, -max, max);
ball.force(dX, dY);
if (ball.hitTestBounds(end)) {
emitter.loc(ball).spurt(20);
ball.dynamic = false;
ball.vis(false);
ball.body.loc(ball.startX, ball.startY);
timeout(3.5, () => {
newCreate()
});
}
});
// we want to find the color of the maze picture around where the ball is
// we will put a wall at anywhere that is not the background color
// so we access the context 2D of the cached picture
var ctx = maze.cacheCanvas.getContext('2d');
var num = 24; // test a 10x10 grid around the ball
var space = 1; // the spacing of the points on the grid
var radius = 1; // the radius of a wall placed at a point
var walls = []; // an array to keep track of the active walls
function newCreate(){
generalCont.removeAllChildren()
maze = new Pic("maze4.png").pos(0,50,CENTER,CENTER,generalCont).cache();
ctx = maze.cacheCanvas.getContext('2d');
num = 24; // test a 10x10 grid around the ball
space = 1; // the spacing of the points on the grid
radius = 1; // the radius of a wall placed at a point
walls = []; // an array to keep track of the active walls
ball.dynamic = true;
ball.vis(true);
emitter.loc(ball).spurt(20);
}
function makeWalls() {
// remove any walls from the last time
loop(walls, wall => {
physics.remove(wall);
});
walls = [];
// loop through our grid
loop(num, i => {
loop(num, j => {
const pointIn = maze.globalToLocal(ball.x, ball.y);
// locate the x and y point on the grid for this i,j index
const x = pointIn.x - num / 2 * space + i * space;
const y = pointIn.y - num / 2 * space + j * space;
if (x < 0 || y < 2 || x > maze.width || y > maze.height-2) return;
// get the color data of the pixel at this grid location
const data = ctx.getImageData(x, y, 1.2, 1.2).data;
// Physics lets you automatically map physics bodies to ZIM objects
// but in this case, we do not need visual objects
// and we are creating many objects - so do not make the ZIM objects
// Physics has methods to add only physics objects
// so this is what we do in this case
// make the wall if the color is darker than the background color
if (data[0] < 150) {
let wall = physics.makeCircle(radius, false);
const pointOut = maze.localToGlobal(x,y);
wall.x = pointOut.x,
wall.y = pointOut.y;
// add the wall to our array of walls
walls.push(wall);
}
});
});
}
This may work for now, I'll work on it further.
You can create any maze you want from the site below.
https://codebox.net/pages/maze-generator/online