Pacman game - Making a wall block his movement - javascript

I'm making a pacman game with Jquery. Pacman's movement is directed by the arrow keys, which triggers a setInterval() that makes him move his width's distance repeatedly, giving the illusion that he is moving Completely straight. Pressing a new key clears the interval and starts him moving somewhere else.
function Player(){
this.left = $('#pacMan').css('left');
/**/
this.top = $('#pacMan').css('top');
/**/
this.rightMove = function(){
if (){
this.left = parseInt(this.left) + 20;
$('#pacMan').animate({'left': this.left}, 100);
}
};
//The object containing the movement method. The empty if statement is the problem I'll get to later.
var timer;
$('body').keydown(function () {
var key = event.which;
window.clearInterval(timer);
timer = window.setInterval(function() {
switch (key) {
case 37:
pacMan.leftMove();
break;
// The keydown function. It's all kind of disjointed, I know.
So the above works fine. My issue however is this: What happens if I put a wall? How would I get him to stop? I am able to do it with one block but not many. Let me explain.
So I have the whole thing laid out on a grid that's the width of pacman. Me appending a div child to one of the grids selects the grid boxes next to it and puts it in an array. My original if statement was that if Pacman's position is shared with the position of the neighboring grid's, one of his movements are disabled.So if he is just left of the block he can't move right, giving the illusion that the block is stopping him from moving.
e.g
If(Pacman.position().left !== gridBox120.position.left(){
pacMan.moveRight()
}
else{
clearInterval()
}
//As long as pacman is not in the spot right next to the block, he can move right.
This works. But what if I want multiple blocks on the stage? How could I get all these things blocks in the if statement? Or would that be the best way to do it?
My plan was to put the neighbouring divs ID in an array and if Pacman's position shares the position of any of the ID's of the items in the array, he can't move right.
I have no idea how to do this. Some sort of iteration? Or maybe an array is not the best idea for this?
If this is not explained properly I'll respond to comments.
Image link. yellow is pacman. purple are the neighbor divs that are sent to arrays

i already did something like this for a brick breaker.
I've tested obj and array for storing blocks. Array is far faster than obj.
My method was : store all the grid in arrays
And verify after each move the left-1, left+1, top-1 and top+1
if (grid[left-1][top] == "block" && move == "left") {
Pacman.stopFunction()
}

Related

How do I keep Transform Control from moving your object if there is a collision, using raycasting?

So I'm using Three.js and I have some cubes inside of a box. I'm using the Transform Control to move the cubes around inside of the box with my mouse. I'd like to use raycasting in order to check for collisions. The question is how to I prevent the transform controller from moving the object if there is a collision? I'd like to stop it if it hits the wall. By the way, I'm on version r81 for Three.js.
UPDATE: I've used the size of the room to constrain the cubes from
moving outside of the room. This seems to work well. Is there a way
to use the cannon.js just for collisions? I don't want the momentum
or gravity or any other feature. JUST the collision check and to stop
it dead in its tracks when there is a collision.
I know this post is from a long time ago, but hopefully a googler finds this helpful. I wasn't able to stop the user from moving my object, but I was able to move it back to its proper position immediately afterward by adding some logic to the render method.
For the original poster's problem with collisions, you could attach an event listener to the transform controls and request the object to be repositioned if it is in an illegal state.
transformControls.addEventListener('objectChange', (e) => {
if (illegalPosition(this.obj.position)) {
needsReset = true;
}
lastPosition = attachedObject.position.clone();
});
and then in your render function
if (needsReset) {
attachedObject.position.set(lastPosition.x, lastPosition.y, lastPosition.z);
}
If this feels a little hacky, that's because it is. But for those of us who don't have the time or skill to read and modify TransformControls.js, I think it may prove helpful.
You could create helper raycaster and place all colliders in separate container. After movement is applied to object move raycaster to its position and test if ray intersects any of other objects in container. If yes: reset previous position for that object. In case of cube colliders you could want to raycast from cube center in multiple directions with half of side length as ray length.
Ben S does have the best and most painless way to implement collision detection with transform controls. Within a event listener.
But I don't know if the time of writing his answer he knew about or if there even was a function called "requestAnimationFrame". All you would have to do for collision detection instead of simply resetting the models position is to set up your render call within a loop (60 fps) by adding "requestAnimationFrame" to your render (I call it animate since that is more descriptive) function.
Since it is in a loop and is called when the every frame the scene is drawn it will just not allow the object to move past the point of collision.
function animate() {
// Called to draw onto screen every frame (60fps).
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
And your event listener would just look like this.
control.addEventListener('objectChange', (e) => {
// Collision detection code here. Set colliding model position here.
// No need to set it in render
});
Old post, I know. But here is a method that is still fairly simple but does not flicker or use ray casting. The biggest catch here is that you have a little bit of a bounce if you move the Transform control really quickly. But otherwise it seems to work fairly well. You can control the precision of the collision by adjusting the step value.
let transStart = null;
//capture objects position on start
control.addEventListener('mouseDown', function(){
transStart = control.object.position.clone();
})
//you'll have to provide your own collision function
control.addEventListener('objectChange', function(e){
if(collision(sphere, cube)){ stopControls() };
});
function stopControls(){
if(control.dragging && stopAt){
//calculate direction object was moving at time of collision
const s = transStart;
const e = control.object.position.clone();
const n = e.clone().sub(s).negate().normalize();
//janky hack nonsense that stops the transform control from
//continuing without making the camera controller go nuts.
control.pointerUp({button:0});
control.dragging = true;
//translate back the direction it came by the step amount and do not
//stop until the objects are no longer colliding.
//Increase the step size if you do not need super precise collision
//detection. It will save calculations.
let step = 0.00005;
while(colliding(sphere, cube)){
sphere.translateOnAxis( n, step ) ;
sphere.updateMatrix();
}
}
}

Go through a sprite and save background-position

In the game that I have, when the player walks up to the number and presses the "m" key one frame of the sprite is skipped.
To clarify, the following is my code that I use to keep track of when the frames should change by storing the position of the frames in a variable:
function animateStar() {
var pos = 0;
$(document).keyup(function(e) {
if (e.keyCode == 77) {
pos -= 32;
$('#n1').css('background-position', pos+'px -0px');
}
});
}
So as you can see, everytime the key code 77 (representing "m") is pressed, the frames will change, since each of my frames has a height and width of 32px.
However, the problem that I am having is that when my player walks away from the object and comes back to it, instead of continuing from where he left off, the frames sort of skip.
Here is my code: http://jsfiddle.net/j40s8gjt/
Since my sprite sheet is composed of numbers, you should be able to see what's up with the code.
Try setting the frame at a number between 3-5, walking away from the object then coming back to it and pressing m again, you should see that it sort of re loops everything.
A possible solution of this might be to store the current position of the object when the player leaves it, but I am not sure how to go about doing so.
I hope I've been clear enough, thank you!
Since you're defaulting to 0 each time you call animateStar() it starts over.
Grabbing the current position is what you need to do instead of defaulting to 0 each time.
in animateStar(), Change this line:
var pos = 0;
to this:
var pos = $('#n1').css('background-position').split('px ')[0] || 0;
That way it gets the current position when it starts, instead of starting from 0 again and resetting the frame.
Working example: http://jsfiddle.net/j40s8gjt/2/

Multiple simultanous animations, simulation of 'animate' easing and one 'step' call for a jQuery collection

Here is the problem, I've got a tree structure of html blocks, global container is of a fixed width(X) and height(Y). When i click one of the blocks on a level, all other blocks shrink to some size, while the clicked one gets enlarged to the leftover space, and the sublevels show up on it's place.
For all the shrinking i'm using default animate function with easing effect, when shrinking 1 level, to avoid enlargement bugs i have to do something like this:
$tabs.not($obj).animate({height:32<<$obj.getVerUp().length+"px"},{duration:300,
step:function() {
$obj.height(function(){
var sum = 0;
$tabs.not($obj).each(function(){
sum += $(this).height();
});
return $obj.getCont().height()-sum+"px";
});
}
});
$tabs are all the tabs of current level, $obj - is the one tab that i want to enlarge
The main problem is:
When i open up a tab that is on a deep level, i have to animate all the tabs of higher levels to shrink a little bit more, thus the $obj X and Y would change, so the current animation has to use new values, but if i call 3 different animations on different levels i'm bound to get a bug, when one of the animations on a deeper level finishes 1 step earlier, while the one on the level above, would enlarge the object by 5-10 more pixels and that space wouldn't be used up.
The second problem is that there has to be about 50 object animating with easing at the same time, which is a little bit overkill.
And the last problem is when i call step callback on animation as shown above, i have a strange feeling that it calls the step separately for each animation of the $tabs collection, while i need 1 step for all the tabs in the list (to avoid unnecessary scripts)
There might be some other way to fix all that, but i have yet to discover all jQuery functions, so from what i see the only way is to simulate easing, and do everything in one single animation.
I don't really want to use setInterval and determining when do i need to clear it plus calculating each of the easing values, if there is a simple way doing it.
Does jQuery has some sort of empty animation easing, e.g.
$().css("height":starth+"px").animate({height:endh},{duration:300,
step:function(fn) {
// all the animation actions here via fn end value
}
});
Thanks in advance.
What I need - is not a completely working solution in code, just some enlightenment in those subjects:
Is there a legal way to call one step function for a collection of animated elements, or, maybe, it does call step once when I use one .animate on collection.
I'd be really appreciated if someone would shed some light over how does jquery handle multiple .animate, would they be used in one global function that works on .setInterval? or would they be having massive number of those .setIntervals that are equivalent to setTimeout (which most browsers can't handle in large amounts);
Is there a way to simulate 'animate' easing, some function name maybe, or a special trick to achieve that (the only thing I see is a hidden element or 'window' property to change maybe)
Or some directed pushes with functions I should study, that could help me achieve my goals
Guess i pretty much found the answer to my questions:
http://james.padolsey.com/javascript/fun-with-jquerys-animate/
Here's the empty animation from the link above with 1 step function with desired values, going to post the result later on if it all works out.
var from = {property: 0};
var to = {property: 100};
jQuery(from).animate(to, {
duration: 100,
step: function() {
console.log( 'Currently # ' + this.property );
}
});
Yes it all worked great, no desynch, and a good speed, since only 1 animate, found making one universal function for the animation - waste of resourses, so it is pretty specific, but still, here it is:
animate: function($obj) {
var T = this;
...
T.arr = new Array();
// gathering the array
$obj.each(function(i){
var size;
T.arr[i] = {obj:$(this), rest:$(this).getSibl(), cont:$(this).getCont()}
if($(this).hasClass("vert"))
{
size = "height";
T.arr[i].to = yto;
}
else
{
size = "width";
T.arr[i].to = xto;
T.arr[i].children = $(this).getChld();
}
T.arr[i].rest.each(function(){
$(this).attr("from",$(this)[size]());
});
});
// animating prop
jQuery({prop:0}).animate({prop:1}, {
duration: 300,
step: function() {
var i;
var P = this;
var newval;
var sum;
var size;
for(i = 0; i < T.arr.length; i++)
{
size = T.arr[i].obj.hasClass("vert") ? "height":"width";
sum = 0;
T.arr[i].rest.each(function(){
// new value of width/height, determined by the animation percentage
newval = parseInt($(this).attr("from")) + (T.arr[i].to-$(this).attr("from"))*P.prop;
$(this)[size](newval);
sum += newval;
});
T.arr[i].obj[size](T.arr[i].cont[size]()-sum);
}
}
});
},

Why does this setTimeout code build up and not terminate?

If you click the body of the html once and wait until the ball is offscreen its fine. However if you clicked 2+ times you'll notice the ball moving faster. When you click the body again to make the ball come back it is still faster then it should be. Why? http://jsfiddle.net/44nwt/10/
-edit- in firefox on my page (i havent tried on jsfiddle) i notice the move func is called repeatably even after the ball has left screen and been removed. Why isnt it existing?
This works (http://jsfiddle.net/44nwt/11/)
there were two issues:
#1 every click creates another instance of ball and ballwrapper, and adds them into the body. It's only necessary to create the instance if it doesn't already exist. So that would look something like this:
$('body').click(function() {
var wrapper = $('.ballwrapper');
if( wrapper.length == 0 ) {
$('body').append('<div class="ballwrapper"><img class="ball" src="http://michaelreid.typepad.com/.a/6a00e54edabd838833011168a00f09970c-800wi"/></div>');
}
MoveCode();
});
#2 You need a gate at the beginning of your MoveCode function, to prevent the "extra" cycles (the ones that get started by each extra click) from proceeding once the ball/ballwrapper has been removed.
function MoveCode() {
var wrapper = $('.ballwrapper');
if( wrapper.length == 0 ) return;
var l = $('.ball').css("left");
var left = parseInt(l);
if (left > parseInt(wrapper.css('width'))) {
//alert('removed');
wrapper.remove();
return;
}
$('.ball').css("left", (left + 60) + "px");
setTimeout(MoveCode, 160);
}
Also note... I changed it to remove the ballwrapper, rather than removing just the ball. Otherwise, if you run it all the way through over and over again, you'll accumulate old, unused ballwrappers in the background.
if (left > parseInt($('.ballwrapper').css('width'))) {
//alert('removed');
$('.ball').remove();
return;
}
If left is undefined (i.e., the ball has been already removed) then the condition is false and the scheduling will be done repeatedly

Why does my my gravity work in this?

http://davzy.com/gameA/
I can't figure out a smart way to get gravity. Now with this it detects which block the character is over but it does't drop to that block!
Is there a better way to do gravity? I'd like to do this without a game library.
I don't know what you mean by "get gravity"; your question is unclear. I assume that if you can detect when the block is over, you can use the following formula:
s(t) = ut + 1/2at2
Where s is the distance at time t, u is the initial velocity (which in your case would be zero), and a is the acceleration (on Earth this is 9.8m/s2). Essentially you would be adjusting the top position of your object based on the value you get at time t (so original top position of object + s(t)). I would imagine you would use some sort of animation loop. Perhaps a setInterval. Maybe others with more experience in Javascript animation can chime in about the best way to implement this. However, this would be the formula that you would be using to figure out where the object is at time t, if it falls.
Basically gravity in a platformer goes like this:
var currentGrav = 0.0;
var gravAdd = 0.5; // add this every iteration of the game loop to currentGrav
var maxGrav = 4.0; // this caps currentGrav
var charPosY = getCharPosY(); // vertical position of the character, in this case the lower end
var colPosY = getColDow(); // some way to get the vertical position of the next "collision"
for(var i = 0; i < Math.abs(Math.ceil(currentGrav)); i++) { // make sure we have "full pixel" values
if (charPosY == colPosY) {
onGround = true;
break; // we hit the ground
}
onGround = false;
charPosY++;
}
Now to jump one could simply do this:
if (jumpKeyPressed && onGround) {
currentGrav = -5.0; //
}
You can, if you want(and understand C), check out my game for a basic platformer(with moving platforms) here:
http://github.com/BonsaiDen/Norum/blob/master/sources/character.c

Categories

Resources