#Frame Logic with OnCollisionEnter2D
1 messages · Page 1 of 1 (latest)
It's more the other way around.
Unity determines when Update is called.
In the background, it gets all the Update() methods from all scripts and run them in sequence.
But that's besides the point.
yeah, but it's like what you put in there, will (try) update every second, or no?
If no specific framerate has been set, Update() will run as often as possible. My PC has around 300 FPS on a blank project.
That means the Update method will run 300 times in one second
It's fine. This is not an easy field, but I'll try to ease this in with your current issue.
yeah, it's a lot to learn haha
Movement is coded in either Update() or FixedUpdate()
- Update runs per visual frame (the game FPS)
- FixedUpdate runs every Physics tick, which by default is 50 times per second, regardless of framerate.
The idea is that anything related to game-logic should be happen equally as often among all players.
While Update() is used for things that need to be more in visual sync.
OnCollisionEnter2D is a physics event, that happens for a single frame.
Since it only runs the first time an object collides, it it mostly used to flip bools, that change behavior.
So in that method you should replace the transform.position line,
with hasTouchedPlayer = true;
Well doesn't it make it move based on time and not framrate since I multiplied it with Time.deltaTime?
OnCollisionEnter2D happens for a single frame.
the first moment the game registers a collision
ah yes
so it can't carry movement over time
Yeah, makes sense.
so we flip a bool, and move the movement logic to Update/FixedUpdate
private bool hasTouchedPlayer;
private void OnCollisionEnter2D(...)
{
if (..) hasTouchedPlayer = true;
}
private void Update()
{
if (hasTouchedPlayer) // Move
}
Once you get that to work, we can work on the correct way to move objects that have colliders (not transform.position)
so that they can interact properly with other colliders
Any questions?
gimme a sec
if (..) hasTouchedPlayer = true; , should the (..) be the ground then? a bit confused
The code is not meant for copying, just a guide to where things are in your script
(...) means you already have something there in your code, and I didn't bother to write it
only 2 methods 😅
it's the existing if-statement in that method
well, if you do that, it will visually move the way you want (great success)
but it will conflict when encountering other colliders, because the physics system is supposed to be solely responsible for moving physics objects (colliders).
Using transform.position is overriding what physics wants to do.
so you can do it just to see how the code actually works
and use OnCollisionEnter and not Stay then? as I have rn
Yes, at least for this one.
Once we nail movement, you can elaborate on the entirety of the mechanic.
(as in, what more you want than just moving)
I was planning making it a platform moving from A to B
Kinda sound very newbie lol, but I'm not sure if this is what you meant.
private bool hasTouchedPlayer;
private void OnCollisionEnter2D(Collision2D OnCollisionEnter2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player")) hasTouchedPlayer = true;
{
}
}
// Update is called once per frame
void Update()
{
if (hasTouchedPlayer) // Move
}
!code
📃 Large Code Blocks
Large code blocks should be posted as links to services like:
https://gdl.space/, https://paste.ofcode.org/, https://hatebin.com/
https://paste.myst.rs/, https://hastebin.com/
📃 Inline Code
Surround code with three backquotes. Not quotation marks.
To get C# formatting the first line should only contain cs or csharp.
Add a comment with a line number if there is an error message.
```cs
// Your code here
```
Do not share screenshots of code unless requested.
// Your code here <--- read that
repost like this
private string name = "code blocks with syntax highlighting";
if-statements can be written in three ways
if (true) DoThing();
if (true)
DoThing();
if (true)
{
DoThing();
}
private string name = "code blocks with syntax highlighting";
after that, just copy it from the website and paste it here?
No, I mean copy your code from inside Visual Studio, directly into Discord
but before pasting it in Discord, make a code-block
oh lol
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OnCollisionMoveGround : MonoBehaviour
{
private bool hasTouchedPlayer;
private void OnCollisionEnter2D(Collision2D OnCollisionEnter2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player")) hasTouchedPlayer = true;
{
}
}
// Update is called once per frame
void Update()
{
if (hasTouchedPlayer) // Move
}
}
oops
edit the post
there
Good stuff
haha took a while
Now, re-read the thing I wrote about if-statements, and fix yours
it's good practice to use { scope brackets }
whichever way you write it, the goal is for the code to be readable
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OnCollisionMoveGround : MonoBehaviour
{
private bool hasTouchedPlayer;
private void OnCollisionEnter2D(Collision2D OnCollisionEnter2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player"))
{
hasTouchedPlayer = true;
}
}
// Update is called once per frame
void Update()
{
if (hasTouchedPlayer)
{
// The old movement code you had
}
}
}
Now I'm kinda confused if I'm supposed to use the Update? Since you refer to it as the old movement code
What I mean is for you to paste the exact line you used for movement in your original example
ah
The first code example I posted, was meant to be an instruction for how to edit the original script
I only specified which changes were to be made
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OnCollisionMoveGround : MonoBehaviour
{
private bool hasTouchedPlayer;
private void OnCollisionEnter2D(Collision2D OnCollisionEnter2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player"))
{
hasTouchedPlayer = true;
}
}
// Update is called once per frame
void Update()
{
if (hasTouchedPlayer)
{
transform.position = transform.position + (Vector3.left * moveSpeed) * Time.deltaTime;
}
}
}
this is what I've got now
oh
if (true) DoThing();
if (true)
DoThing();
if (true)
{
DoThing();
}
like that?
yes that moveSpeed doesn't fit in the context lol I removed it
wait what?
yes, it should be there. You removed it?
no, just the float but I put it back dw
post the full script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OnCollisionMoveGround : MonoBehaviour
{
private bool hasTouchedPlayer;
public float moveSpeed = 8;
private void OnCollisionEnter2D(Collision2D OnCollisionEnter2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player"))
{
hasTouchedPlayer = true;
}
}
// Update is called once per frame
void Update()
{
if (hasTouchedPlayer)
{
transform.position = transform.position + (Vector3.left * moveSpeed) * Time.deltaTime;
}
}
}
here
but I fixed it, and it's starting to resemble what I want the platform to be
now it moves by itself, but for every frame I touch it, it speeds up
kinda
That would be from your Rigidbody colliding and adding force
the code is either On/Off
no Off at the moment
yeah
wdym on/off?
You could copy the contents of OnCollisionEnter2D,
and paste them into OnCollisionExit2D, but setting the bool false
Then you'd have a platform that only moves when the player is touching it.
like the player?
Right now the code is activating the movement
but the movement never stops
yea
alr
You mean like having a void OnCollisionExit ?
Yes.
that like stops it after one trigger
That's an example of something you could do, to easily add immersive functionality
yea alr
Enter is the frame the colliders start touching
Exit is the frame they stop touching
Player touches platform - it moves
Player leaves platform - it stops moving
private void OnCollisionExit2D(Collision2D OnCollisionExit2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player"))
{
hasTouchedPlayer = false;
}
}
kinda like that?
yeah, but still nice
Is this platform supposed to move between A and B all the time, or only activate like a ferry for transport?
Like a ferry
So when you collide, it will take you there
and preferably so it can take you back
so ideally, for it to move a second time, you'd have to step off, and back on (or at least jump)
or use an interface, like a button
Yeah
yeah i meant for example so you could go back later and return with it
not so it will do it constant
as you said lol, step on and off
Alright, good stuff.
The immediate issue might be jumping.
Is jumping possible?
Yes
yeah alr, I have basic movement
Okay, now let's do proper Physics movement
In order to move, colliders need to be able to produce Force,
for which they will require a Rigidbody2D
Add that component to the platform object.
Then in the script:
public Rigidbody2D rb;
and drag the Rigidbody component into your script's Rigidbody2D field.
should I use the same object and script as before?
You can keep the old script, and create a new one, copy the old code into it, and proceed from there.
I made it a prefab, guess it will automatically save the old script with it?
it is a reference to that single script. It will update with changes.
ah ok
so if you want the prefab to use the new script
you'll have to open the prefab itself, remove the old, and add the new.
Then the prefab instances in the scene need to be updated with the new override from the parent asset.
Or, you can just copy the script to a folder outside the project, to keep it for historical reasons, and keep using the same one, with no extra fuzz 😅
good
so when you type Rigid in Visual Studio, does it suggest Rigidbody and Rigidbody2D ?
noo
!ide
If your IDE is not autocompleting code
or underlining errors, please configure it:
• Visual Studio (Installed via Unity Hub)
• Visual Studio (Installed manually)
• VS Code*
• JetBrains Rider
• Other/None
*VS Code's debugger plugin is unsupported.
We recommend using VS or Rider instead.
Go through the appropriate guide, and let me know when it works.
Should be simple enough. 90% don't need help with this process.
alr
If you're among those who do need help, just make sure you've read all the steps.
Yes, very.
Good stuff. You're now at all allowed to get help on this server 😆
(it's a requirement, because coding without intellisense is just madness)
so btw it's 10 PM here, so I'm not sure if I'll be able to help you complete this in time
but at worst, we can go through some basics, and you can explore some short youtube tutorials on moving platforms
my own script is nearly 300 lines
yeah no worries
and I haven't actually made a platform that transports a player
which can be done by parenting the player to the platform object (children move with their parents)
so, Rigidbody movement
Ah yes
yeh alr
fixed it
The script example gives a good idea of how that method is used.
ignore the stuff in Start()
Just read Update()
so, I don't really need anything from before exept for the rigidbody?
You do need everything. We're just going to modify the movement part.
ok yeah
makes sense
But wont it kinda confuse it having multiple lines telling it to move
It won't have that, because you will comment out or remove the lines we are replacing.
public Rigidbody2D rb;
public float moveSpeed = 8;
private Vector2 direction;
private void FixedUpdate()
{
direction = rb.transform.forward;
rb.MovePosition(rb.position + (direction * moveSpeed * Time.deltaTime));
}
direction is just there to make it readable
Velocity is the product of a Vector direction multiplied by speed
The online script example uses Time.fixedDeltaTime
which is the proper way, but Time.deltaTime is universal; it simply knows how much time has passed since last time.
alr
Now, wrap that movement code inside the same if-statement as the old code
and see if it works the same way
In this case, you'd just rename Update() to FixedUpdate()
well, since the platform uses physics it falls down in the void since its levetating
yeah think I'll have to do that, removing the gravity makes it a bit goofy hahah
hmm well it does move but it's also like a wobbly board
It swings with it's physics
putting body type to static kinda fixed it
Since I haven't made a transporting platform, and it's late, I don't think this solution will be perfect.
That said, the reason is probably because of physics simulations, when interacting with the player.
One solution is to make the platform's rigidbody kinematic (it's a checkbox)
That way it won't be affected by physics, but only it's own movement code.
static objects shouldn't be able to move
or am I just that rusty on this?
yep, console went crazy mad lmao
yellow errors
but yeah kinematic works
Probably no need to freeze Y axis then
Does the player move with the platform, or do you need to move to keep up with it?
It doens't move with the character, I need to run along
for making it switch direction, couldn't you make it like switch direction every time you collide with it? like you jump and collide again, and it switches kinda?
That you could
I think it would make sense, because if you went right with it, to get back, you jump on it again later and then it will switch to left
I'm not entirely sure if what I'm thinking about will solve that issue.
When you're on the platform, Pause the Editor playback, and make your player a Child of the platform
then resume Play
ok
depends entirely on what type of fun or cursed mechanics you want in your game ^^
yeah, it works
Nice.
Then we just have to realize that through code.
yea
post your full script again
also, I can walk but lik 1% of normal speed while bein a child of the platform
hm 😅
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OnCollisionMoveGround : MonoBehaviour
{
private bool hasTouchedPlayer;
public float moveSpeed = 8;
public float deadZone = -50;
private Vector2 direction;
public Rigidbody2D rb;
private void OnCollisionEnter2D(Collision2D OnCollisionEnter2D)
{
if (OnCollisionEnter2D.gameObject.CompareTag("Player"))
{
hasTouchedPlayer = true;
}
}
private void OnCollisionExit2D(Collision2D OnCollisionExit2D)
{
if (OnCollisionExit2D.gameObject.CompareTag("Player"))
{
hasTouchedPlayer = false;
}
}
// Update is called once per frame
void Update()
{
if (hasTouchedPlayer)
{
transform.position = transform.position + (Vector3.left * moveSpeed) * Time.deltaTime;
}
if (transform.position.x < deadZone)
{
Debug.Log("OnTriggerGroundMove Deleted");
Destroy(gameObject);
}
}
private void FixedUpdate()
{
if (hasTouchedPlayer)
{
direction = rb.transform.forward;
rb.MovePosition(rb.position + (direction * moveSpeed * Time.deltaTime));
}
}
}
then it might not be an ideal solution
I mean could make the speed go crazy high while colliding lmao
haha, technically, you could work around anything
but that would probably just become a bigger problem later
hmm yes
I'm not sure which one of these supports a Rigidbody player
but you should probably find something useful in there
Moving between A and B is covered in all of them.
The easiest way is to have game objects which represent the waypoints
That one doesn't cover Physics, but if it works, then it works
After completing it, you can see if replacing transform.position with rb.position works the same. It would be more correct.
hmm was working on the rotation part but got stuck at how to rotate it lol