For people looking to advance their skills in Scratch and add gravity and jumping to your 2D game. Simple to use and easily optimizable. This can work for platformers or other fun-skilled games.
To emulate the effect on scratch, we would start by creating a gravity variable. Make sure you are viewing the code of the sprite you wish to apply the effect to.
Step 1: Create a new variable called Gravity.
Step 2: Change the Gravity
You are going to want the gravity to slowly speed up while your player or other object is not touching the ground, color, or other collision detected object. You can do this by creating this script.
When Flag is Clicked:
Forever:
If(not touching[object or color]):
Change(gravity) by -1
If(touching[object or color]):
Set(gravity) to 0
This will allow the gravity to slowly increase when the player is not colliding with the desired object. Now, you can apply this gravity by changing the y position of the player by gravity.
Full script:
When Flag is Clicked:
Forever:
If(not touching[object or color]):
Change(gravity) by -1
end
If(touching[object or color]):
Set(gravity) to 0
end
Change Y By(gravity)
Extra: If you want to take it to another level, you are able to add a jump effect. It is quite easy.
Script:
When Flag is Clicked:
Forever:
If(touching[object or color] and [key(up) is pressed]):
Set(gravity) to (desired jump height value)
Uhm, so assuming there are walls and ceilings in your platformer
First, you need the following variables
X_Vel (X's velocity)
Y_Vel (Y's velocity)
Alongside the X and Y of the player
And then assuming that the ground is a sprite called Level
Then you can make this for gravity
Y_Vel = Y_Vel - 1
Y = Y + Y_Vel
And then for floor collision
if (Touching Level) then
Ground <- Custom block
if (Space Pressed) then
Y_Vel = 10 <- For jumping
else
Y_Vel = 0 <- Player doesn't melt to the floor
end
end
And then for the custom "Ground" block
Define Ground
repeat (abs(Y_Vel))
if (Touching Level) then
Y = Y + ((abs(Y_Vel) / Y_Vel) * -1)
end
end
end
You might notice that the character won't actually go all the way back up if it doesn't hit the ground hard enough, and that's intentional and needed for wall collisions
You might also notice that the character might also go downwards too if Y_Vel is positive, which is also intentional and needed for ceiling collision
Moving on, we're going into the left and right code since we haven't finished the wall collision code, and because you said platformers. We're going to need velocity to move the player for the wall collisions so this is what goes next:
if (A Pressed) then <- Or Right arrow key
X_Vel = -10
end
if (D pressed) then <- Or Left arrow key
X_Vel = 10
end
X = X + X_Vel <- Move player
Feel free to edit the code above for more features like sprinting, acceleration, rolling, etc.
And then finally, wall collision
if (Touching Level) then
X = X + (X_Vel * -1)
X_Vel = 0
end
That's it... Unless you want to improve the wall collision and mimick the ground/ ceiling collision. Well, here you go!
Of course, it'd be much better if you just watch a YouTube tutorial on this problem.
Related
I'm making a game where I have a skeleton as a game object:
Since this skeleton is an enemy, I want to make it walk on its own, and turn around as it reaches the edge, and so on. I managed to make it walk like so:
void Update() {
if (isWalking) {
body.velocity = new Vector2((isFacingLeft ? -1 : 1) * speed, body.velocity.y);
.
.
.
where isWalking is set to true from the beginning for testing purposes, speed is 5, and isFacingLeft is a boolean I want to flip whenever the skeleton reaches an edge, initially it is false, so the skeleton travels to the right without stopping.
So the idea I had is make use of OnCollisionEnter2D which should work since the skeleton is on top of the platform game object, and use the collision object to get different bounds:
From the picture, if the game object platform can be called L and its width y, then I'm thinking of getting the necessary bounds of it by finding Lx and Lx + y. Then, if the skeleton's width can be called x, I would want to measure the transform.position.x of the skeleton and check: if it faces right, and transform.position.x > Lx + y - x (or maybe x / 2 to approach it a bit more to the edge), then flip the isFacingLeft boolean. If it's facing left and transform.position.x < Lx + x (or x / 2), flip the boolean.
However, if I try logging the left edge (via collider.transform.position.x) and the skeleton position (via transform.position.x), I get starting values of 6.4596, 5.943441, meaning that the skeleton somehow starts before the platform. Is it possible that transform is not the right property to check for bounds in this case? How then can I ensure I'm using the desired values to check edges? If anyone knows, please comment even if you have questions about my approach, as going over the thought process really helps to get an answer.
So as suggested by pocokknight on reddit, I tried implementing ray casting, so that there is a ray projecting from a bottom corner of the skeleton sprite depending on what position it should face, achievable via SpriteRenderer.bounds.size. If the ray projected doesn't hit anything the position the skeleton would face flips. This enables the skeleton to turn around back and forth forever :)
RaycastHit2D hit = Physics2D.Raycast(new Vector2(transform.position.x + ((enemyWidth / 2) * direction), transform.position.y - enemyHeight / 2), transform.TransformDirection(new Vector2(1 * (direction), -1)), 1f);
Of course, this is a very simple execution of the function, and I could probably think of scenarios where the raycast check could fail (such as if the player object is right on its path when it should be checking for empty ground), but thus far it's a progress I'm happy with
I'm trying to implement this in Physica, my Scratch-based physics engine. I tried adding it and the ball glitched out (couldn't move on the x axis at all). Does anyone know how to do this?
If it's a physics engine, then every object should have added variables for speed, and then you manipulate the speed:
To change the speed:
When ... (whenever your drag release is)
set Vx to 10
this example has a drag function:
https://en.scratch-wiki.info/wiki/Draggable_Sprite_Feature
In the physics engine, speed constantly moves your object:
When green flag
forever
add Vx to x
add Vy to y
#boisvert pretty much answered your question. But if you want to sense drag releasing, use this code:
when green flag
set drag mode to draggable
forever
wait until touching mouse pointer and mouse down
wait until not mouse down
point toward mouse pointer
set V to distance to mouse pointer * 2
along with this:
when green flag
forever
set V to V*0.9
move V steps
if on edge, bounce
It's not the most perfect code, but it will work
Example: https://scratch.mit.edu/projects/558479500/
I'm making a game with unity3D that ball is rolling on the ground.
When I set single large ground block, and using Rigidbody.AddForce() in Unity3D. ball is rolling fine.
But if I set multiple small ground blocks, ball is jumping unexpectly on boundary of blocks. Even block size, positions and intervals are exactly matched.
Can I solve this problem?
(I can't freeze position Y of ball. because ball needs gravity.)
-edited-
Here is my code to move ball by AddForce(). when I clicked.
private void MoveBall(Vector3 pos)
{
Ray HookRay = Camera.main.ScreenPointToRay(pos);
int layerMask = LayerMask.GetMask("Block");
RaycastHit objectHit;
float distance = Mathf.Infinity;
if (Physics.Raycast(HookRay, out objectHit, distance, layerMask))
{
moveTo = objectHit.point;
Vector3 forceValue = moveTo - transform.position;
forceValue.y = 0f;
rb.AddForce( forceValue * charSpeed, ForceMode.Impulse);
}
}
And here is screenshot of Unity3D
I placed 3x1x3 cube blocks and arranged all positions Y to 0.
There are no cracks or gaps on it.
This likely comes from inaccuracies in the physics engine. They are there because the engine tries to cut corners to speed up processing. You can make it cut less counters (at the cost of speed) by following a few steps. First thing to try is to make the rigidbody do collision detection continuous. You can also try turning on interpolation. There are also more advanced ways where you will do physics updates more often than your frame rate. But I would try the simpler options first. They’re often enough.
Go to Edit -> Project Settings -> Physics and play with default contact offset, maybe make it much smaller like 0.00001 and try it. Another way you can freeze the y and then when some condition happens you can unfreeze it again.
Ok I'm developing a game in which you land a rocket ship while avoiding asteroids... Pretty simple. I have two UI Text elements that are meant to display the current vertical and horizontal velocity. I searched around and came up empty in terms of unity having a built in function to get the current velocity of a 2D rigidbody so I came up with this:
void Update () {
shipVelocity = Mathf.Abs((lastPosition.y - spaceShip.transform.position.y) / Time.deltaTime);
shipAngularVelocity = Mathf.Abs((lastPosition.x - spaceShip.transform.position.x) / Time.deltaTime);
uiText = "Vertical Velocity: " + shipVelocity;
currentVelocityText.text = uiText;
uiText = "Horizontal Velocity: " + shipAngularVelocity;
currentAngularVelocityText.text = uiText;
lastPosition = spaceShip.transform.position;
}
Basically it just does your standard velocity = delta position / delta time but something is wrong. The numbers bounce all over the place and after the ship has landed and is completely stationary the numbers still bounce around from 0-1. While it's flying the numbers rapidly change from what I think is an accurate velocity to 0 and back - so fast it basically just looks like it's blinking.
Could it be it's just calling it too fast? I.e. frame rate too high? If so how can I slow it down?
Thnx!
If you are updating a Rigidbody, it is important to put your update logic in "FixedUpdate()". This version of update is called at a set rate (default 50x/sec) and therefore should be used for updating physics logic. Link: https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html
This is common in games as it separates the framerate (draws/sec) from the update logic (updates/sec), meaning that of the framerate drops, the games underlying physics are not altered.
So my friend and I are making some 2D game, we are using some custom character controller, so we are not using rigidbody2D. Now we have some sort of catapult which needs to eject the player in a projectile-motion style.
We've done it for the catapult which shoots the player straight up
In inspector you can decide how much units do you want player to jump and how much does it need to get to reach max height.
So here is the code for the catapult that shoots the player up.
float ejectInicialY = (jumpHeight - ( player.physics.gravity * Mathf.Pow(timeToReachMaxHeight, 2) / 2)) / timeToReachMaxHeight;
float ejectVelocityY = ejectInicialY + player.physics.gravity * Time.deltaTime;
player.physics.playerVelocity = new Vector2(ejectVelocityY, 0f);
I tried to apply the same formulas for the X coordinate, but it doesn't work well.
Any help would be greatly appreciated.
This is ultimately a physics problem.
You are calculating current velocities by determining the acceleration of the object. Acceleration of an object can be determined from the net force acting on the object (F) and the mass of the object (m) through the formula a = F / m. I highly recommend reading some explanations of projectile motion and understanding the meaning of the motion equations you are using.
Vertical Direction
For the vertical direction, the net vertical force during the jump (assuming no air drag, etc.) is player.physics.gravity. So you apply your motion formulas assuming a constant acceleration of player.physics.gravity, which you've seemed to have accomplished already.
Horizontal Direction
Becausegravity does not commonly act in the horizontal direction, the net horizontal force during the jump (assuming no air drag, etc.) is 0. So again you can apply your motion formulas, but this time using 0 as your acceleration. By doing this, you should realize that velocityX does not change (in the absence of net horizontal force). Therefore the X coordinate can be determined through (in pseudo-code) newPositionX = startPositionX + Time.deltaTime * velocityX