private void MoveProjectile()
{
transform.position = transform.position + transform.up * projectileSpeed * Time.deltaTime;
}
Been a few years since I’ve messed with unity so apologies if anything is outdated or wrong.
For 1, make sure the scripts are attached to two different objects and then in one object you reference the other object to see that value. Make sure the field is publicly assessable via get, not set.
Code examples: https://stackoverflow.com/questions/35657376/c-sharp-unity-trying-to-access-a-variable-from-another-script
For 2, transform.up is a vector2 (x,y grid) or vector3 (x,y,z grid) object that defines the up direction. For vector2 <x,y>; up is <0,1>, down is <0,-1>, left is <-1,0>, right is <1,0>.
Direction.up * speed * time is you distance the object should move from its current location on the grid.
Like I don't understand how to pull an integer variable from one script (i.e. "currentPlayerHealth") and use it in another script in the same game/scene? Like as a test I wanted to write a script that just pulled that value and displayed it in the console log. But when I try to do that it has no idea what currentPlayerHealth is since it's a variable in another script. I feel like this is the most simple 101 stuff since you write modular and keep various pieces in their own scripts.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class gameManager : MonoBehaviour
{
public int playerHealth;
// Start is called before the first frame update
void Start()
{
playerHealth = 20;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("s"))
{
playerHealth--;
}
if (Input.GetKeyDown("w"))
{
playerHealth++;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class healthCheck : MonoBehaviour
{
public GameObject manageObj;
public gameManager manager;
public int health;
// Start is called before the first frame update
void Start()
{
manager= manageObj.GetComponent<gameManager>();
}
// Update is called once per frame
void Update()
{
health= manager.playerHealth;
}
}
Drag the gameObject that has the manager script on it onto the one the has the second script in the field that will have appeared. Apparently this is the best way to do this in unity. for better understanding of transform.up:
you can think of it as a constant, it's literally just a stand-in for a number as skullfuckers said
you use transform.up instead of the literal number value because there could be a situation where your game might need to change what is considered to be "up," and in those cases you could change transform.up, rather than needing to track down all the places in the code where you typed a magic number that meant "up" at the time
sounds like fun, bebpo. post your project when your done!
Just curious, which class are you taking? I want to get into Unity dev (I do C# and .NET coding from time to time at work) but was looking for some good tutorials.
Do any of you code for your jobs?
Quoteprivate void MoveProjectile()
{
transform.position = transform.position + transform.up * projectileSpeed * Time.deltaTime;
}
I understand everything in that sentence except what "transform.up" is doing? It's saying the new position is the old position + speed x time. Which makes sense. I just don't get what transform.up is doing there.
private void MoveProjectile()
{
transform.position += transform.up * projectileSpeed * Time.deltaTime;
}
Like I don't understand how to pull an integer variable from one script (i.e. "currentPlayerHealth") and use it in another script in the same game/scene? Like as a test I wanted to write a script that just pulled that value and displayed it in the console log. But when I try to do that it has no idea what currentPlayerHealth is since it's a variable in another script. I feel like this is the most simple 101 stuff since you write modular and keep various pieces in their own scripts.
Gonna be watching lots of youtube tutorials this weekend and trying to write some scripts.
public class BulletScript : monobehaviour
{
[serializefield] float bulletSpeed, bulletDamage;
void Update()
{
this.transform.position += vector3.forward * time.deltatime * bulletSpeed; // yeah I know what I said before about this being the bad way of doing this, but you know how to do this
}
public void DeleteBullet()
{
// you can call this from another script, eg when you spawn it with instantiate set it to self destruct after n seconds if it doesnt hit anything
}
void OnCollisionEnter(Collision col) // whatever you hit will be accessible from *this* script as col
{
if (col.gameObject.name == BadGuy)
{
col.EnemyScript.TakeDamage(bulletDamage);
// you have a pointer to 'col' because the bullet just hit it, so you can access scripts on the things you just hit,
// and trigger its EnemyScript via its public TakeDamage method, which takes a paramter youre sending from this bullet
// - ie how much damage its doing
}
}
}
public class EnemyScript: monobehaviour
{
[serializefield] float myHealth;
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == bulletPrefab)
{
col.BulletScript.DeleteBullet();
// delete the bullet that just hit you
// Note I wouldn't actually do this code this way, because order of execution might mean you delete the bullet before it does the damage,
// but I'm just reinforcing how you can get a couple of scripts to talk to each other on a collision
}
}
public void TakeDamage(float damage)
{
// this is called from the bullet hitting
myHealth -= damage;
if (myHealth<=0) { fuck im dead }
}
}
for better understanding of transform.up:
you can think of it as a constant, it's literally just a stand-in for a number as skullfuckers said
you use transform.up instead of the literal number value because there could be a situation where your game might need to change what is considered to be "up," and in those cases you could change transform.up, rather than needing to track down all the places in the code where you typed a magic number that meant "up" at the time
Thanks, so I'm guessing you define transform.up somewhere? That might be the issue, the code I'm working with from my class doesn't define it anywhere and uses it like a built in command in Unity.
I'm gonna assume the default for transform.up is like 1 unit? So transform.up + speed (3) x distance (5) = go forward 18 units.
The reason I'm having a hard time understanding this initially is without defining transform.up, if transform.up = 1, then it seems extrafloues? Like if I would think you'd do transform.position (which say is (5,10) = transform.position + speed (3) x distance (5) and you'd still get 18, so from (5,10) you'd move to (23, 28)?
[lots of good stuff]
Though for this 2d shooter project, being 2d and all I should just be using vector2s the whole time I think?
Thanks, this is extremely informative. A lot of what you wrote in the code sections is flying over my head but will spend time and try to parse and understand it all later when I have some time.
One comment though, you said the way the projectile code is written is bad and you should be using 2drigidbody. The thing is that my class project using the assets they give us (including that projectile code, which they say is the most simple script included), is using 2drigidbody. Like we had a whole session on rigidbody because when we first made the ship player and put an enemy with projectiles in the projectiles would just pass through the player ship until we added 2drigidboy and definied the hitbox.
Not sure what that means because this is beyond my scope of understanding that the projectile code is setup that way along with using rigidbody for collision.
Also I want to understand what you're saying about time.delta and shmup slowdown because if I can add shmup slowdown to this with a ton of bullets/enemies that would be kind of cool.
Haha, ok that does make sense! I was wondering how Unity would apply a single digit transform to a vector3 and yeah if it applies to the Z axis you're gonna be bad rats fucked. So that makes sense.
Though for this 2d shooter project, being 2d and all I should just be using vector2s the whole time I think?
private Vector3 GetScrollDirection()
{
Camera camera = Camera.main;
if (camera != null)
{
Vector2 screenPosition = camera.WorldToScreenPoint(transform.position);
Rect screenRect = camera.pixelRect;
if (!screenRect.Contains(screenPosition))
{
return scrollDirection * -1;
}
}
return scrollDirection;
I understand pretty much everything in that code, outside rb.velocity which I guess is a built in Unity thing about movement that I should look up the Unity help to see what it does.
This code worked and my little enemy sprite moves back and forth like space invaders now.
bool goingLeft=true;
if (pos.X>=12) { goingLeft=false; }
else if (pos.X<=-12) { goingLeft=true; }
if (goingLeft) { transform.pos += speed; }
else { transform.pos -= speed; }
// same again for Y boundaries if you need them
// you can also do somthing like
movementX = mathfclamp(-12,12)(input.getaxis("horizontal"));
movementY = mathfclamp(-8,8)(input.getaxis("vertical"));
// to lock player movement to bounds
You can also automagically generate those bounds by getting camera information (ie what the camera can see = playspace boundaries)So then I looked up the script my class has for enemy which includes movement modes. One thing is the class I'm taking doesn't use localScale but like every tutorial I see online uses localScale. I like how in the code above you just set the localScale for x as either positive (1) or negative (-1) to determine the direction on the X movement.
Without localScale...I don't know how to simply set right x = 1, or x = -1 for movement direction.
if (movingRight) { transform.pos += Vector2.Right * Movespeed * Time.deltatime; }
else { transform.pos += Vector2.Left * Movespeed * Time.deltatime; }
The way my class script does it is...complicated. The enemy script is really long and maybe I'll put more of it up later since I tried going through it and understanding each line (that's one way I'm trying to learn, is read all the scripts provided and try to understand each line). For movement on a scrolling movement the code is:
...
Now I can follow that until this part which is all gibberish to me and seems highly complex for just figuring the direction to go left or right?Quoteprivate Vector3 GetScrollDirection()
{
Camera camera = Camera.main;
if (camera != null)
{
Vector2 screenPosition = camera.WorldToScreenPoint(transform.position);
Rect screenRect = camera.pixelRect;
if (!screenRect.Contains(screenPosition))
{
return scrollDirection * -1;
}
}
return scrollDirection;
"Rect screenRect = camera.pixelRect"
Creates a rectangle called screenRect, ok I get that. But I don't know what camera.pixelRect means. Also that if statement kinda breaks my brain.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test_Move : MonoBehaviour
{
public float EnemyMoveSpeed = 1.0f;
Vector3 localScale;
public bool movingRight = true;
public float leftBoundary = -1.0f;
public float rightBoundary = 1.0f;
Rigidbody2D rb;
void Start()
{
localScale = transform.localScale;
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (transform.position.x > rightBoundary)
movingRight = false;
if (transform.position.x < leftBoundary)
movingRight = true;
if (movingRight)
moveRight();
else
moveLeft();
}
void moveRight()
{
movingRight = true;
localScale.x = 1;
transform.localScale = localScale;
rb.velocity = new Vector2(transform.localScale.x * EnemyMoveSpeed, rb.velocity.y);
}
void moveLeft()
{
movingRight = false;
localScale.x = -1;
transform.localScale = localScale;
rb.velocity = new Vector2(transform.localScale.x * EnemyMoveSpeed, rb.velocity.y);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test_Move : MonoBehaviour
{
public float EnemyMoveSpeed = 1.0f;
public bool movingRight = true;
public float leftBoundary = -1.0f;
public float rightBoundary = 1.0f;
void Update()
{
if (transform.position.x > rightBoundary)
movingRight = false;
if (transform.position.x < leftBoundary)
movingRight = true;
if (movingRight)
transform.position.x + (1 * EnemyMoveSpeed);
else
transform.position.x + (-1 * EnemyMoveSpeed);
}
}
Also I wonder what happens if I get rid of rigidbody & velocity. Will try & see...
transform.position += direction * speed * Time.deltatime
movement code you posted earlier, and had figured out how it works?rb.position += direction * speed * Time.fixeddeltatime
into your fixed update loop - if you're not trying to use Full Fat Physics, often 'rolling your own' Reduced Fat Physics (ie just the collisions part, and writing your own specific movement code) can get nicer results - you'll notice this especially when you're doing shit like creating frictionless physics materials to avoid inertia, or making gravity ridiculously high, or fucking with your players mass to try and get the 'feel' you want; when you start doing stuff like that, thats the time to just set things up how you want them from scratch.Also is there an easy way to backup versions of code before you fuck with them and potentially break them and forget how it was setup before you broke it?
Right now I'm doing Unity right click "show in folder" -> copy .cs file to desktop & rename as backup. Feel like there must be an easier way to do this.
Visual studio tells me "only assignment, call increment, decrement, await and new object expressions can be used as a statement"
See if you can figure it out.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test_Move : MonoBehaviour
{
public float EnemyMoveSpeed = 1.0f;
public bool movingRight = true;
public float leftBoundary = -1.0f;
public float rightBoundary = 1.0f;
void Update()
{
if (transform.position.x > rightBoundary)
movingRight = false;
if (transform.position.x < leftBoundary)
movingRight = true;
if (movingRight)
transform.position = new Vector2(transform.position.x + (1* EnemyMoveSpeed * Time.deltaTime), transform.position.y);
else
transform.position = new Vector2(transform.position.x + (-1* EnemyMoveSpeed * Time.deltaTime), transform.position.y);
}
}
using System;
using System.Collections;
using UnityEngine;
public class Enemy : MonoBehaviour
{
Player _target;
public Bullet BulletPrefab;
public float SideBulletAngle = 30f;
public float FireInterval = .2f;
void Awake()
{
_target = FindObjectOfType<Player>();
}
private void OnEnable()
{
StartCoroutine(Fire());
}
private IEnumerator Fire()
{
while(enabled)
{
Fire(-SideBulletAngle);
Fire(0);
Fire(SideBulletAngle);
yield return new WaitForSeconds(FireInterval);
}
}
void Fire(float angle)
{
var bullet = Instantiate(BulletPrefab, transform.position, Quaternion.identity);
bullet.Initialize(_target.transform.position, angle);
}
}
Instead of trying to make the best full fledged shmup ever in my first week of code. I really need to learn the basics and practice and do them over and over until I'm comfortable with the simple stuff before delving into the intermediate things you'd actually want to use to make a game.
Having said that, if you want me to explain anything in particular better, let me know - I'm not doing a multiline quote of your like, 10 posts in a row though :lol
Dedicate your energy towards rom translations instead
public class Boundaries : MonoBehaviour
{
private Vector2 screenBounds;
private float objectWidth;
private float objectHeight;
void Start()
{
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
objectWidth = transform.GetComponent<SpriteRenderer>().bounds.size.x / 2;
objectHeight = transform.GetComponent<SpriteRenderer>().bounds.size.y / 2;
}
void LateUpdate()
{
Vector3 objectPosition = transform.position;
objectPosition.x = Mathf.Clamp(objectPosition.x, -screenBounds.x + objectWidth, screenBounds.x - objectWidth);
objectPosition.y = Mathf.Clamp(objectPosition.y, -screenBounds.y + objectHeight, screenBounds.y - objectHeight);
transform.position = objectPosition;
}
}
If you just want to 'move' a BG image, you could just make it a texture and just scroll it?
It would then work with your bounds stuff if I understand you correctly, as it won't actually be moving anywhere, it will just look like it is.
https://docs.unity3d.com/ScriptReference/Material.SetTextureOffset.html
(this is also a pretty nice way of doing parallax scrolling in a 2D game)
(it grabs your screen dimensions and then halves them? why? Shouldn't it grab your screen dimensions and then just set max X/Y as the max X/Y of your screen?).
I still don't like that the ship warps back to the initial start point when you die. I wish I had the time/skill to figure out how to make it respawn in place and just blink for the 2-3 sec invuln state. I could probably do the blink animation (just set it blank every other frame?), but I don't know how to code that change.
// lets declare some variables
int spawnCooldown=120;
bool spawnProtection=false;
Transform deathPos;
Renderer rend; // cache a reference to this in your Awake() method, because you're about to abuse the shit out of it
void OnDeath() // call this when ya die
{
deathPos = transform.position;
spawnProtection=true;
spawnCooldown=120;
}
// on your respawn call, teleport the player to deathPos;
void Update() // lets put the rest of this shit in your update loop
{
if (spawnProtection) // add this check to your takedamage call with a return, so if they have spawn protection enabled, no damage is done.
// you might want to turn off collision too while its active...?
{
if (spawnCooldown <= 0) { rend=enabled=true; spawnprotection=false; return; }
}
spawnCooldown --; // this decreases this variable by 1; at 60fps, this will be 2 secs of invulnerability at a default value of 120
if ((spawncooldown % 2) == 0) // this is a Modulo; its basically the 'remainder' after a division. In this case, if the cooldown timer is an odd number it wont run, if its even it will; ie it will turn the sprite on / off rapidly.
{
rend.enabled=true;
}
else { rend.enabled=false; }
}
Sprites are pretty fun. I have zero x 00000 art drawing skills and I still made a decent enemy that animates and looks ok moving around with my move script. My biggest problem with art is going to be that I don't know how to do shade/lighting to give a less flat/basic look. I just never took art courses to understand how things should look with lighting.
(http://www.grimoireassemblyforge.com/dudebro2/site/wp-content/uploads/2010/12/nintexpost.jpg)
:salute
That's 13 years ago now.
Cuyahoga made up the title to mock another user who accused him of being a pedophile because he purchased and enjoyed the game Imagine: Babyz Fashion.
The game, originally scheduled for release in summer 2010
was later pushed to 2011
The developers published for free level codes that allow users to download those [two custom Super Mario Maker] levels. They cautioned against spoiler culture when playing through these levels, as they might potentially ruin some crucial story beats from the yet-to-be-released Dudebro II.
[In 2017] they announced plans to purge all references to NeoGAF, and start work under a new team on a spiritual successor. No further statements confirming the game is in active development were ever issued.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Splash_Screens : MonoBehaviour
{
public static int SceneNumber;
void Start()
{
if (SceneNumber == 1)
{ StartCoroutine(ToSplashTwo());
}
if (SceneNumber == 2)
{ StartCoroutine(ToSplashThree());
}
if (SceneNumber == 3)
{ StartCoroutine(ToSplashFour());
}
if (SceneNumber == 4)
{
StartCoroutine(ToLevelOne());
}
}
IEnumerator ToSplashTwo()
{
yield return new WaitForSeconds(3);
SceneNumber = 2;
SceneManager.LoadScene(2);
}
IEnumerator ToSplashThree()
{
yield return new WaitForSeconds(3);
SceneNumber = 3;
SceneManager.LoadScene(3);
}
IEnumerator ToSplashFour()
{
yield return new WaitForSeconds(3);
SceneNumber = 4;
SceneManager.LoadScene(4);
}
IEnumerator ToLevelOne()
{
yield return new WaitForSeconds(3);
SceneNumber = 5;
SceneManager.LoadScene(5);
}
}
else { Debug.log("I fucked up somewhere because this shouldn't run!"); }
(or a more relevant error message) in every IF block to get into the habit of evaluating all code pathsI've made so many songs and I dislike them all :'(
Making music is not hard. Making good music that comes out the way it is in your head is hard. I used to play guitar so I have some sense of this but there I just play notes on guitar without thinking of where on the scale they are. Never was good at reading music. Trying to find the note I'm looking for here can be tough!
Yeah, I would definitely suggest while you're still learning things you are very strict with your logic flow by - for example - always having anCode: [Select]else { Debug.log("I fucked up somewhere because this shouldn't run!"); }
(or a more relevant error message) in every IF block to get into the habit of evaluating all code paths
Also, I can't say that's a bad tutorial, and if nothing else you can use it as an example of using coroutines as timers, but its a bit weird because Unity has had built in Splash Screens for uhhhh quite a few fucking editions now
(https://i.imgur.com/6NQW6UY.png)
But like I say, nothing wrong with knowing how to do scene transitions;
I'd have probably made those coroutines actually check the levels loaded before moving on rather than fixed wait times, but like I say thats useful info to know how to do anyway
If {posting on Bore, doPost(); Else debugLog"why aren't you posting on Bore;}"
void doPost(){
Type up blah blah blah;}
If {posting on Bore, StartCoRoutine(doPost()); Else debugLog "why aren't you posting on Bore;}
IEnumerator doPost {
Type up blah blah balh;}
I always wanted to make a game that took elements from top-down zelda GBA games like Link's Awakening, Oracle of Age, etc, and I started watching tutorials and shit, but that shit is hard. If I had to do my life over again i'd definitely learn 2 code though. I remember in highschool I managed to make a little Zelda movement simulator in flash (walking around, bunping against walls, being carried by water) but I can't even imagine being able to learn how to do that now.
blah blah Update()
{
check child();
]
void check child();
{ if GameObject.Child = SetActive(true)
{debugLog("Still Alive");
Else
{Destroy(gameObject);}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlanCheck2d : MonoBehaviour
{
void Update()
{
checkInnerody();
}
private void checkInnerody() {
Debug.Log("test" + transform.GetChild(0).gameObject.activeSelf);
if (transform.GetChild(0).gameObject.activeSelf == (false))
{
Destroy(gameObject);
}
else
{
// do whatever you want if child is inactive
}
}
}
I always wanted to make a game that took elements from top-down zelda GBA games like Link's Awakening, Oracle of Age, etc, and I started watching tutorials and shit, but that shit is hard. If I had to do my life over again i'd definitely learn 2 code though. I remember in highschool I managed to make a little Zelda movement simulator in flash (walking around, bunping against walls, being carried by water) but I can't even imagine being able to learn how to do that now.
Destroy(this.gameObject);
Debug.Log("GettingHere2");
gameObject.SetActive(false);
Debug.Log("GettingHere2");
gameObject.SetActive(false);
Destroy(this.gameObject);
Debug.Log("GettingHere2");
gameObject.SetActive(false);
if (teamId == 1)
{ Destroy(this.gameObject); }
else
{ Debug.Log("Team ID: " + teamId); }
Tbh at this point I don't know the difference between a coroutine and a method.
Also in your post you say you'd have it check the levels, what does that mean?
[ienumerator,thing]
dostuff;
yield return new wait for seconds 5;
do some more stuff;
end code block
So I want to add a "Lives: 0" display in the UI to show the current lives outside of the debug screen.
The int with currentLives is in the health.cs script attached to the player.
The UI Display is in a separate script and using the class UIElements to override updateUI to display a text string. I can't get this to work under the health.cs script since it won't let me have the script be a child of MonoBehaviour and UIElement.
The simple thing would be to figure out how to grab that int currentLives that is on the Player in the Health.cs script from my Display script. But this is a bit beyond me and goes back to trying to get separate scripts to interact. I can find the gameObject that is player with Find.gameObject.Player, right? So how do I go from there to getting the variable from a script that's attached to it?
using Unity.UI; (this lets you acces the UI.Text directly)
class UI_Timer : Monobehaviour
{
public Text uiTextElement;
int timerValue=0;
Update()
{
uiTextElement.Text = "Timer: "+ timerValue;
timerValue++;
}
}
Sage, any chance you're available for a bit today to help me on some stuff? There's just a link of code that I don't know yet which is blocking off a ton of possibilities by having things interact with each other and I need help figuring that out if I want to do more interesting things with my game.
Like I'm trying to have a 3d polygon object attack the player in this 2d game. The problem being the physics colliding interaction between a 3d object and 2d object. Initially my bullets passed right through the 3d object even with the 3d collider on. I googled it and the get around I found was you make a hidden 2d object within the 3d object (as a child gameobject) and throw on the 2d rigid body & collider.
Not sure how to do that in terms of transitioning. I'm guessing if I can figure out how to work with timers or other object interactions I can say after health reaches 50, run the score movement drop script and then spawn EROCS text which would just be a duplicate of the score text with different text in the field).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public Text uiTextElement;
int timerValue = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
uiTextElement.[b]Text[/b] = "Timer: " + timerValue;
timerValue++;
}
}
I'm trying to use that Timer code you posted to display a timer text and I'm getting an error:Lowercase T https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Experimental.UIElements.TextElement.html ie uiTextElement.textCode: [Select]using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public Text uiTextElement;
int timerValue = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
uiTextElement.[b]Text[/b] = "Timer: " + timerValue;
timerValue++;
}
}
The bold is giving me this error:
'Text' does not contain a definition for 'Text' and no accessible extension method 'Text' accepting a first argument of type 'Text' could be found (are you missing a using directive or an assembly reference?)
I'd have a variable that keeps track of the phase and then use a switch to change stuff based on which phase it is. Dunno if that's dumb tho
I'm trying to use that Timer code you posted to display a timer text and I'm getting an error:Lowercase T https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Experimental.UIElements.TextElement.html ie uiTextElement.textCode: [Select]using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public Text uiTextElement;
int timerValue = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
uiTextElement.[b]Text[/b] = "Timer: " + timerValue;
timerValue++;
}
}
The bold is giving me this error:
'Text' does not contain a definition for 'Text' and no accessible extension method 'Text' accepting a first argument of type 'Text' could be found (are you missing a using directive or an assembly reference?)
public class Timer2 : MonoBehaviour
{
public Text uiTextElement;
int timerValue = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
uiTextElement.text = "Insanity: " + timerValue;
timerValue++;
if (timerValue == 1000)
{ displayText(); }
}
public void displayText()
{ transform.GetChild(0).gameObject.SetActive(true); }
}
uiTextElement.text = "Insanity: " + timerValue;
timerValue++;
if (timerValue == 600)
{ displayText1(); }
if (timerValue == 1000)
{ displayText1(); }
if (timerValue == 1800)
{ displayText1(); }
if (timerValue == 3100)
{ displayText1(); }
if (timerValue == 6600)
{ displayText1(); }
if (timerValue == 7900)
{ displayText1(); }
if (timerValue == 8300)
{ SceneManager.LoadScene(17); }
}
public void displayText1()
{ transform.GetChild(0).gameObject.SetActive(true); }
About the only thing I still don't know how to do is display ship lives :| Not a big deal, though players probably want to know how many lives they have left.You have your lives stored as a variable somewhere right? And in your UI code you're displaying the value of the timer.
Also one thing that would be real helpful is, is there a trick to using different versions of the same scripts in different scenes?
Yeah, that was it. The missing link that's the game changer. Got text stuff going, my scene changes are working. Now that I have a timer I can do lots of stuff. Since the text childs destroy themselves after a few seconds the next one is always child(0), so the code was pretty easy!
...
About the only thing I still don't know how to do is display ship lives :| Not a big deal, though players probably want to know how many lives they have left.
public Text livesTextUI;
void UpdateLivesUI(int lives) // call this method whenever you change the lives value, and send it your updated lives variable
{
livesTextUI.text = "Lives Remaining: " + lives; // or however you want to phrase this; eg could be livesTextUI.text = lives + " / " + maximumLives;
}
dragging and dropping your lives UI text component into the variable fieldfloat timerCurrent=0f; // timer value
bool runTimer=false; // for a simple start / stop toggle
public Text timerTextUI;
void StartTimer(float tickrate)
{
runtimer=true;
InvokeRepeating("MyTimer", 0, tickrate);
}
void MyTimer()
{
if (!runtimer) { StopTimer(); return; }
timercurrent++;
timerTextUI.text = timercurrent;
}
void StopTimer()
{
runtimer=false;
CancelInvoke();
}
void RestartMyTimer(float tickrate)
{
timercurrent=0;
StartTimer(float tickrate);
}
Lives are probably conceptually the same as the time. You just need to point your UI code to where you're storing the lives.
One spot I need multiple scripts is for my story scenes because there is no good way to grab the currentscene number as an int?
SceneManager.LoadScene(int)
specifically takes an int - I've literally never used a string for that stuff; you can get current scene with Scene.buildIndex by doing something likeint GetScene()
{
scene = SceneManager.GetActiveScene();
return(scene.buildIndex);
}
When this is done, the next thing I want to do is read/watch some long detailed classes on how to get different scripts to talk to each other and to practice that a ton until I'm comfortable. Because it is one of the major things I still don't know how to do. Like in my game the gamemanager script freely calls methods that are in other scripts that if I tried doing that in my own script the game would balk saying that method doesn't exist in my script I wrote. Other scripts then send things to the game manager and back and forth. It seems the game manager can do that, but to do that with other scripts it's more complicated. If I want to write a fresh script that says "yo, give me the current values of variables in 5 different scripts running on this object right now" I don't know how to make that work?
OnCollisionEnter (Collider col)
{
int damage=10;
Health variableRepresentingAScriptCalledHealth = col.getcomponent<Health>();
variableRepresentingAScriptCalledHealth.TakeDamage(damage);
}
Nah, thats definitely not right...Code: [Select]SceneManager.LoadScene(int)
specifically takes an int - I've literally never used a string for that stuff; you can get current scene with Scene.buildIndex by doing something like
Code: [Select]int GetScene()
{
scene = SceneManager.GetActiveScene();
return(scene.buildIndex);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Timer2 : MonoBehaviour
{
float timerCurrent = 0.0f; // timer value
bool runTimer = false; // for a simple start / stop toggle
public Text timerTextUI;
void StartTimer(float tickrate)
{
runTimer = true;
InvokeRepeating("MyTimer", 0, tickrate);
}
void MyTimer()
{
if (!runTimer) { StopTimer(); return; }
timerCurrent++;
timerTextUI.text = "Time: " + timerCurrent;
}
void StopTimer()
{
runTimer = false;
CancelInvoke();
}
void RestartMyTimer(float tickrate)
{
timerCurrent = 0;
StartTimer(1.0f);
}
// Start is called before the first frame update
void Start()
{
StartTimer(1.0f);
}
// Update is called once per frame
void Update()
{
if (timerCurrent == 1)
{ displayText1(); }
if (timerCurrent == 4)
{ displayText1(); }
if (timerCurrent == 8)
{ displayText1(); }
if (timerCurrent == 12)
{ displayText1(); }
if (timerCurrent == 20)
{ displayText1(); }
if (timerCurrent == 41)
{ displayText1(); }
}
public void displayText1()
{ transform.GetChild(0).gameObject.SetActive(true); }
}
couple of compile errors.
timerTextUI.text = timerCurrent.ToString();
StartTimer(float,tickrate);
Also I see you're using tickrate instead of time.deltatime. Is this better for a more stable time between all different computers? I.e. I want big boss to jump out on screen at 5 seconds in on the level because at 5.5 secs something else will fall into the screen covering it and at 4.5 seconds the same thing so only during that 5 second window is the screen open for the boss to jump in.
Void start{startTimer (1.0f)}
Then if currentTime = 5 seconds = boss jump out?
private IEnumerator BossSetup()
{
yield return new WaitForSeconds(5f);
Boss.gameObject.SetActive(true);
yield return new WaitForSeconds(0.5f);
BossAnimation();
yield return new WaitForSeconds(0.5f);
OtherThingHappens();
Ugh, this is acting way less accurate than the old timer. Not sure what's going on.
I have the first text/gamechild destroy at 2 secs and the next trigger at currentTime = 3 seconds, but it doesn't. Only at 4 secs or later. Same with trying like 3.5/3.6/3.7, I get nothing before 4 secs. It's like the timer isn't working before 4 seconds?
if (timerCurrent == 1)
{ displayText1(); }
if (timerCurrent == 4)
{ displayText1(); }
The one at 1 second doesn't run though...
But I got it all working just putting it under start for the first one and first timer related one being at 30 ticks (.1f tickrate) which is fine. Just seems like there's a brief lag with the tickrate before it can run commands?
InvokeRepeating("MyTimer", 0, tickrate);that zero means 'run this shit immediately' - you can delay it there, which might stop it missing the first set value...?
Oh, speaking of multiple scripts. How would you write a multi-use respawn script if you want to respawn at different offsets each time? Just have the offset be a public variable?
Vector2 Setspawn(int spawnIndex)
{
Vector2 spawnPos;
//whatever you're doing to offset the spawn here, eg if you spawn one unit further to the left on each death
spawnPos = new Vector2((0-spawnIndex), 0);
}
void DoSpawn(transform spawnPos)
{
newSpawn = spawnPos + SetSpawn(timesDied);
instantiate(player, newSpawn, transform.rotation);
}
or whatever.But, when the object dies, if I have a death animation it's not scaled :| I think this is because the gamemanger script has it setup where the object and its death animation are separate because you put for each object "death effect" where you drag a prefab which is the death animation & sound effect for that thing. Not sure if there's a quick solution to this other than to go back to the animation program and resize the animation loop at the scale you're going to have the sprite in game so the animation matches on death.
FIXED IT. There's a bit on sprite compression where it's on normal compression and I changed it to best quality. Problem was the sprite was too large because I made it too awesome :(
Will link it later in another day or two.
Which software are you using for spritework?
I recommend Aseprite.
again there are myriad ways to do anything, but an easy one is if you have a simple object that is "textured" with just one color, like green for a life bar, and have its width set to a calculation based on 100% of the boss's health, and simply reduce its width as life goes down (revealing a UI element behind it that is red to show how much of the bar has depleted)
void Update()
{
RectTransform RT = GetComponent<RectTransform>();
Debug.Log("RTpositiony = " + RT.position.y);
}
public class Test_MoveSpecial2 : MonoBehaviour
{
public float EnemyMoveSpeed = 1.0f;
public bool GoingUp = false;
public float DestinationY = 0;
RectTransform m_RectTransform;
private void Start()
{
m_RectTransform = GetComponent<RectTransform>();
}
void Update()
{
Debug.Log("RT " + m_RectTransform.anchoredPosition.y);
if (GoingUp == true && m_RectTransform.anchoredPosition.y <= DestinationY)
{
transform.position = new Vector2(transform.position.x, transform.position.y + (1 * EnemyMoveSpeed * Time.deltaTime));
}
if (GoingUp == false && m_RectTransform.anchoredPosition.y >= DestinationY)
{
transform.position = new Vector2(transform.position.x, transform.position.y + (-1 * EnemyMoveSpeed * Time.deltaTime));
}
}
(https://i.imgur.com/L5w3DKO.jpg)
How do I get that -24 number? I want to set an (if > -24) move upwards.
I'm trying RectTransform and this code just gives me the RectTransform is 0.0, 0.0 no matter where the text object starts on screen and I can only manipulate it relative to that.Code: [Select]void Update()
{
RectTransform RT = GetComponent<RectTransform>();
Debug.Log("RTpositiony = " + RT.position.y);
}
#1 - A script on each enemy to search the scene at every update and when the boss uhhh changes sub-state to running death animation to then start running their own death animations? This is actually a bit complicated because it requires not just getting objects and setting them true/false but changing settings within their component scripts. Maybe there's a simpler way to do this?
public gameobject explosionPrefab; // or a dummy object that plays their death anim then deletes
public gameobject[] minions; // the [] means this is an ARRAY, or basically a list of all the types of gameobject you add here
void BossSpawnCodeBlock() // or whatever
{
for (int i = 0; i<minions.length; i++) // this will cycle though each member of the Array and run the below code on each one
{
instantiate (explosionPrefab, minions[i].transform.position, minions[i].rotation);
Destroy(minions[i]);
}
}
In the end this is super nitpicking, but improving transitions and stuff is the kind of polish that goes a long way! Hell, on that note when the final boss appears it would be nice to lean how to do a transition effect so it like wavy lines fizzles into existence. Right now the scene loads and there's an empty space and then it just POPS into existence and starts spewing bullets instantly. For other bosses I have them come down from off-screen but this boss should start in the middle of the screen so either it's there the second the scene loads and instantly firing bullets (I'd need to mess with the timer to pause this) or it pops into existence a few seconds later which I'm ok with and is how it is currently. Just would be nice to learn how to make an effect for bringing it into the scene.
Is there a way to modify my script to make the movement increments like canvasUI.gameobject.transform.y instead of transform.y to move it up or down on the canvas based on its position relative to the canvas (the text is a child of the canvas)?
screenshot doesn't illustrate this that well but you can shoot right through this specific set of walls for some reason
(https://i.imgur.com/cK6k1IM.png)
I know it doesn't really matter just wanted to point it out, they look like they're individual objects so maybe those 4 don't have some property set that every other wall does?
You have a lot of nice little touches in your game that beginners usually don't have - were they part of the course, or did you add them?
Things like 'leading' the camera with your crosshair rather than the camera following the player, and having particle onhit effects on bullet collisions
#1 - A script on each enemy to search the scene at every update and when the boss uhhh changes sub-state to running death animation to then start running their own death animations? This is actually a bit complicated because it requires not just getting objects and setting them true/false but changing settings within their component scripts. Maybe there's a simpler way to do this?
You'd do this in a similar way that your object pool script worked; if those enemies are non killable before the boss (as I think they are having played it...?) you could do something likeCode: [Select]public gameobject explosionPrefab; // or a dummy object that plays their death anim then deletes
public gameobject[] minions; // the [] means this is an ARRAY, or basically a list of all the types of gameobject you add here
void BossSpawnCodeBlock() // or whatever
{
for (int i = 0; i<minions.length; i++) // this will cycle though each member of the Array and run the below code on each one
{
instantiate (explosionPrefab, minions[i].transform.position, minions[i].rotation);
Destroy(minions[i]);
}
}
which will delete all the objects you've added to the array, and play a one shot explosion / death anim where they were.
If those enemies ARE killable, this won;t work though, as it will break the array, like you did earlier with the bullet pooling by deleting rather than disbaling and repurposing.
You CAN do pretty much the same thing with a LIST though, as long as when you kill a minion you remove it from the list so when it does the FOR loop its only cycling through things that exist
In the end this is super nitpicking, but improving transitions and stuff is the kind of polish that goes a long way! Hell, on that note when the final boss appears it would be nice to lean how to do a transition effect so it like wavy lines fizzles into existence. Right now the scene loads and there's an empty space and then it just POPS into existence and starts spewing bullets instantly. For other bosses I have them come down from off-screen but this boss should start in the middle of the screen so either it's there the second the scene loads and instantly firing bullets (I'd need to mess with the timer to pause this) or it pops into existence a few seconds later which I'm ok with and is how it is currently. Just would be nice to learn how to make an effect for bringing it into the scene.
So what I'd suggest for this rather than making a bespoke animation for it appearing (the 'right' way to do this) would be that you can set the gameobjects material renderer to solid black (and maybe add some transparency) and then fade it in from black ("shadow", again, maybe with some trasparency) to solid coloured / fully opaque. when its material has fully changed to its 'real' colour, you can then allow it to start taking damage - you might wanna kill the player too if they didn't take the hint about the giant fucking shadow monster below them fading into existence right before combat phase starts.
You could also help sell this with some particle animations with 'negative' velocity, so it looks like particles are 'assembling' at the sprite outline to 'create' it (normal particle velocity would have particles moving away from their spawn point, not towards it, and make the spawn object type the sprite edges)
Is there a way to modify my script to make the movement increments like canvasUI.gameobject.transform.y instead of transform.y to move it up or down on the canvas based on its position relative to the canvas (the text is a child of the canvas)?
I'd generally recommend if you wanna do cool UI movements, get yourself a tweening solution and just use that, but in this case you can probably do what you want to do by going to your canvas properties and changing it from ScreenSpace - Overlay to WorldSpace; this will - as it might suggest - make the Canvas option appear in the actual playable gamespace, at the gamespace coords, and take all the same kinds of values any other gameobject in worldspace would
a while back I loaded up an old backup hard drive and my virus scanner found an ancient virus buried in a zip of VST plugins that I'm sure I downloaded from kazaa :lol
I think that's most of my thoughts on the process. Was fun! Learned a lot! Have some basic background now for my next game which unfortunately is a 2d platformer and I don't have a lot of interest or interesting ideas for a platformer as it's not one of my favorite genres. But as I take the class and learn what I can do (including learning how to appropriately do tilemaps) I'm sure ideas will pop into my head.
One thing that hopefully I'll learn in this 2d platformer class is a lot of these world/town/dungeon tilesets are just like one PNG file with a bunch of blocks and I'm not sure what the correct way to use them is? When I made my walls in stage 1 of my game I just cut and pasted from MS Paint a square from the giant PNG and saved it as a new png and that's my texture. Is there a way you're supposed to auto-slice up these single image tilemap things to get a bunch of different usable tiles?
Ideally I'd like a program where there is a single database of every bar I've ever created that continually grows and when I make songs I can just pull them into the song and see if they work for the current track. Apparently this kind of program is called Ableton Live or FL Studio. It's just kind of bogus for game development that these are so expensive when like Asesprite and a lot of other tools are like $20-30 affordable.
For someone who writes software using C#, VB.NET, and Javascript (accounting/business software), how easy is Unity to pick up and learn?
Any good tutorials to create a simple 16-bit style turn based RPG?
I'm feeling a bit of a creative streak and want to get out an RPG but not sure if I should go the RPG Maker or the Unity route. I feel Unity may be a bit more flexible, especially in the case of a battle system, but RPG Maker would enable me to get off the ground MUCH quicker (I made some RPG Maker 2000 game back in 2002 based on my college friends and it was the talk of my dorm for a good hot minute).
but it looks like the next upcoming RPG Maker is called Unite and is literally intended to run within Unity :whoo
public class FullHealthPickup : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision)
{
// Only Heal if colliding with the player
if(collision.tag == "Player")
{
Health playerHealth = collision.gameObject.GetComponent<Health>();
playerHealth.ReceiveHealing(playerHealth.maximumHealth);
Destroy(this.gameObject);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This is the base class for other pick up scripts to inherit from
/// </summary>
public class Pickup : MonoBehaviour
{
[Header("Settings")]
[Tooltip("The effect to create when this pickup is collected")]
public GameObject pickUpEffect;
/// <summary>
/// Description:
/// Standard unity function called when a trigger is entered by another collider
/// Input:
/// Collider2D collision
/// Returns:
/// void (no return)
/// </summary>
/// <param name="collision">The collider2D that has entered the trigger</param>
private void OnTriggerEnter2D(Collider2D collision)
{
DoOnPickup(collision);
}
/// <summary>
/// Description:
/// Function called when this pickup is picked up
/// Input:
/// Collider2D collision
/// Return:
/// void (no return)
/// </summary>
/// <param name="collision">The collider that is picking up this pickup</param>
public virtual void DoOnPickup(Collider2D collision)
{
if (collision.tag == "Player")
{
if (pickUpEffect != null)
{
Instantiate(pickUpEffect, transform.position, Quaternion.identity, null);
}
Destroy(this.gameObject);
}
}
}
Instantiate(pickUpEffect, transform.position, Quaternion.identity, null);
protected virtual void OnCollisionEnter2D(Collision2D collision)
{
if (collision.transform.tag == "Player")
{
AttemptToOpen();
}
}
For someone who writes software using C#, VB.NET, and Javascript (accounting/business software), how easy is Unity to pick up and learn?
Oh and I want to do a PnC Adventure Game and it falls into the same question of 2d rpgs and VNs of whether it makes any sense to do a 2d PnC Adventure game in Unity vs just using Adventure Game Studio?
The advantages people seem to say about GameMaker Studio vs Unity is that you can do stuff quicker, and it has a better interface, so you can get it running and prototype your game fast and see what works and that it's easier to match things up consistently because it uses pixels instead of units. Disadvantages is that GML is less versatile for larger projects. Also GMS isn't good for projects with multiple people working on it, whereas Unity is.
QuoteInstantiate(pickUpEffect, transform.position, Quaternion.identity, null);
Is basically the only line of real code in there, I'm trying to understand what they're doing. With pickUpEffect they're handing off the "what do I do with this" to a different prefab that it'll run at that current objects position and rotation, right? So this code is basically doing nothing other than say "on collision with pickup do whatever prefab you slot in"? Also why is there a null there?
Declaration
public static Object Instantiate(Object original);
Declaration
public static Object Instantiate(Object original, Transform parent);
Declaration
public static Object Instantiate(Object original, Transform parent, bool instantiateInWorldSpace);
Declaration
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);
Declaration
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
Also looking at the code for how Doors work in this, why is it using a protected virtual void vs just void? Haven't seen protected and virtual before.
Also I will try to comment on all code in this project.
I am terrible and did not write a single comment in all my code in my first game.
Sorry, I know that's extremely bad practice :shh
Honestly, that is OK for a first-class. If you do coding first, it would take a very long time to get into the fun bits.
Honestly, that is OK for a first-class. If you do coding first, it would take a very long time to get into the fun bits.
I dunno, I'm not really sure of the benefit of doing 'extra' stuff like object pooling in a My First Unity Project that you're specifically pitching as a 'My First Unity Prohect' when you're not going to be hitting any of the reasons why object pooling is a long-term good thing to know; likewise, you really don't need to understand things like polymorphism or virtual classes / interfaces / inheritance to make basic trigger volumes open doors and pick up power ups.
Like... you can show someone how to make a fun platform game in unity just explaining the basics of rigidbodies; you don't need to go into the details of things like character controller collision flags, until you need to start differentiating between things like 'istouchingfloor' and 'istouchingwall' to do things like wall slides / wall jumps, or mario style brick bashing.
Spent so many hours last week and over the weekend trying to learn piano and trying to translate short tunes I'd make on a virtual piano to a midi note program. Never sounds the same. I figured if I can make the title screen song it'll get me going for the whole project, but no luck. It's supposed to be a slow sad melancholic piano tune, but I haven't really learned how to make those. As a side effect I've made a couple decent songs that I can use elsewhere in the future.
for (int i = 0; i < object.GetChildCount(); ++i)
{
setactive(object.GetChild(i)(true);
}
gameobject yourUICanvasForYourPopUp;
Oncollisionenter()
{
yourUICanvasForYourPopUp.setactive(true);
}
Oncollisionexit()
{
yourUICanvasForYourPopUp.setactive(false);
}
For the second bit, isn't the problem that the child object will be set active false as default so you can't have the collision occur to active it and set it true? That's why I'm attaching it as a child to a gameobject that's active with colliders (but invinsible opacity).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// this is a box trigger, so it needs a box collider
[RequireComponent(typeof(BoxCollider))]
public class BasicTrigger : MonoBehaviour
{
// cache collider
BoxCollider col;
// expose trigger target
[SerializeField]
GameObject targetObject;
// drop down for trigger behaviour
enum TriggerType
{
OneShotActivate, // run once, then stop
Destroy, // destroy target then stop
ToggleOnOff, // turn thing on while in trigger area, turn off when you leave
ToggleOffOn // turn thing off while in volume, on when leave
};
// expose in editor
[SerializeField] TriggerType triggertype;
// boolean to stop scripts after a one shot has activated
bool oneShot;
// on awake cache references
void Awake()
{
col = GetComponent<BoxCollider>();
}
// setup default values
void Start()
{
col.isTrigger = true;
oneShot = false;
}
// unity specific method; will draw the outlines of the trigger volume in an obvious red colour in the editor window
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(transform.position, new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z));
}
// what do we do when something enters this trigger volume?
void OnTriggerEnter(Collider other)
{
if (oneShot) { return; } // stop if it was a oneshot thats fired
else if (triggertype == TriggerType.OneShotActivate){ OneShotActivate(); }
else if (triggertype == TriggerType.Destroy) { OneShotDeactivate(); }
else if (triggertype == TriggerType.ToggleOnOff) { TargetTurnOn(); }
else if (triggertype == TriggerType.ToggleOffOn) { TargetTurnOff(); }
else Debug.Log("Entered Trigger");
}
// what do we do when something leaves this trigger volume?
void OnTriggerExit(Collider other)
{
if (oneShot) { return; } // stop if it was a oneshot thats fired
else if (triggertype == TriggerType.OneShotActivate){ return; }
else if (triggertype == TriggerType.Destroy) { return; }
else if (triggertype == TriggerType.ToggleOnOff) { TargetTurnOff(); }
else if (triggertype == TriggerType.ToggleOffOn) { TargetTurnOn(); }
else Debug.Log("LEft Trigger");
}
void OneShotActivate() { oneShot = true; TargetTurnOn(); }
void OneShotDeactivate() { oneShot = true; TargetTurnOff(); }
void TargetTurnOn() { targetObject.SetActive(true); }
void TargetTurnOff() { targetObject.SetActive(false); }
}
void TargetTurnOn() { transform.GetChild(0).gameObject.SetActive(true); }
void TargetTurnOff() { transform.GetChild(0).gameObject.SetActive(false);; }
Public int TakeDamage(int dmg)
{
int deathValue=100;
myHealth-=dmg;
if (myHealth<=0) { DoDeathAnim(); return(deathValue); }
else return(0);
}
gameobject enemy;
currentScore+=enemy.getcomponent<EnemyHealth>().TakeDamage(bulletDamage);
public int GetHealth()
{
return(currentHealth);
}
public void SetHealth(int change)
{
currenHealth+=change;
if (currentHealth > maxHealth) { currentHealth = maxHEalth; return; }
else if (currentHealth <= 0) { currentHealth = 0; DoDeathSequence(); return; }
}
For the second bit, isn't the problem that the child object will be set active false as default so you can't have the collision occur to active it and set it true? That's why I'm attaching it as a child to a gameobject that's active with colliders (but invinsible opacity).
I think I said earlier, getting used to unity, think of it like pumbing or electrical engineering, where you can have triggers and components as seperate things, and then 'wire them up' in the inspector - you don't have to turn the trigger volume 'off' ever, you just need to 'plumb' the thing you want to turn on/off into in the inspector.
Lemme give you my generic trigger script; just drag and drop whatever you want to be enabled/disabled into the slot, then set how you want the trigger to workCode: [Select]using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// this is a box trigger, so it needs a box collider
[RequireComponent(typeof(BoxCollider))]
public class BasicTrigger : MonoBehaviour
{
// cache collider
BoxCollider col;
// expose trigger target
[SerializeField]
GameObject targetObject;
// drop down for trigger behaviour
enum TriggerType
{
OneShotActivate, // run once, then stop
Destroy, // destroy target then stop
ToggleOnOff, // turn thing on while in trigger area, turn off when you leave
ToggleOffOn // turn thing off while in volume, on when leave
};
// expose in editor
[SerializeField] TriggerType triggertype;
// boolean to stop scripts after a one shot has activated
bool oneShot;
// on awake cache references
void Awake()
{
col = GetComponent<BoxCollider>();
}
// setup default values
void Start()
{
col.isTrigger = true;
oneShot = false;
}
// unity specific method; will draw the outlines of the trigger volume in an obvious red colour in the editor window
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(transform.position, new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z));
}
// what do we do when something enters this trigger volume?
void OnTriggerEnter(Collider other)
{
if (oneShot) { return; } // stop if it was a oneshot thats fired
else if (triggertype == TriggerType.OneShotActivate){ OneShotActivate(); }
else if (triggertype == TriggerType.Destroy) { OneShotDeactivate(); }
else if (triggertype == TriggerType.ToggleOnOff) { TargetTurnOn(); }
else if (triggertype == TriggerType.ToggleOffOn) { TargetTurnOff(); }
else Debug.Log("Entered Trigger");
}
// what do we do when something leaves this trigger volume?
void OnTriggerExit(Collider other)
{
if (oneShot) { return; } // stop if it was a oneshot thats fired
else if (triggertype == TriggerType.OneShotActivate){ return; }
else if (triggertype == TriggerType.Destroy) { return; }
else if (triggertype == TriggerType.ToggleOnOff) { TargetTurnOff(); }
else if (triggertype == TriggerType.ToggleOffOn) { TargetTurnOn(); }
else Debug.Log("LEft Trigger");
}
void OneShotActivate() { oneShot = true; TargetTurnOn(); }
void OneShotDeactivate() { oneShot = true; TargetTurnOff(); }
void TargetTurnOn() { targetObject.SetActive(true); }
void TargetTurnOff() { targetObject.SetActive(false); }
}
You can have an absolute fucking ton of trigger volumes in a scene; if they don't have a meshrenderer enabled they 'cost' fuck all in terms of rendering, and if they're set as triggers they cost almost fuck all until they're actually interacted with (there's a nominal 'cost' in that they exist in the scene and are pre-allocated accordingly).
You can gain a minor performance saving by setting them to 'static' in the inspector checkbox too (so the engine knows to never bother trying to do any physics or lighting calculations on them) - that's just a good practice to get into for things that will never move.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// this is a box trigger, so it needs a box collider
[RequireComponent(typeof(BoxCollider2D))]
public class BasicTrigger : MonoBehaviour
{
// cache collider
BoxCollider2D col;
// expose trigger target
[SerializeField]
GameObject targetObject;
// drop down for trigger behaviour
enum TriggerType
{
OneShotActivate, // run once, then stop
Destroy, // destroy target then stop
ToggleOnOff, // turn thing on while in trigger area, turn off when you leave
ToggleOffOn // turn thing off while in volume, on when leave
};
// expose in editor
[SerializeField] TriggerType triggertype;
// boolean to stop scripts after a one shot has activated
bool oneShot;
// on awake cache references
void Awake()
{
col = GetComponent<BoxCollider2D>();
}
// setup default values
void Start()
{
col.isTrigger = true;
oneShot = false;
}
// unity specific method; will draw the outlines of the trigger volume in an obvious red colour in the editor window
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(transform.position, new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z));
}
// what do we do when something enters this trigger volume?
private void OnTriggerEnter2D(Collider2D collision)
{
if (oneShot) { return; } // stop if it was a oneshot thats fired
else if (triggertype == TriggerType.OneShotActivate) { OneShotActivate(); }
else if (triggertype == TriggerType.Destroy) { OneShotDeactivate(); }
else if (triggertype == TriggerType.ToggleOnOff) { TargetTurnOn(); }
else if (triggertype == TriggerType.ToggleOffOn) { TargetTurnOff(); }
else Debug.Log("Entered Trigger");
}
// what do we do when something leaves this trigger volume?
private void OnTriggerExit2D(Collider2D collision)
{
if (oneShot) { return; } // stop if it was a oneshot thats fired
else if (triggertype == TriggerType.OneShotActivate) { return; }
else if (triggertype == TriggerType.Destroy) { return; }
else if (triggertype == TriggerType.ToggleOnOff) { TargetTurnOff(); }
else if (triggertype == TriggerType.ToggleOffOn) { TargetTurnOn(); }
else Debug.Log("LEft Trigger");
}
void OneShotActivate() { oneShot = true; TargetTurnOn(); }
void OneShotDeactivate() { oneShot = true; TargetTurnOff(); }
void TargetTurnOn() { targetObject.SetActive(true); }
void TargetTurnOff() { targetObject.SetActive(false); }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This class will make the player a child of whatever it is attached to
/// It is meant to be used with the moving platform to keep the player moving along with the platform
/// </summary>
public class PlayerChilder : MonoBehaviour
{
/// <summary>
/// Description:
/// Built-in Unity function that is called whenever a trigger collider is entered by another collider
/// Input:
/// Collider2D collision
/// return:
/// void (no return)
/// </summary>
/// <param name="collision">The collider that entered the trigger</param>
private void OnTriggerEnter2D(Collider2D collision)
{
MakeAChildOfAttachedTransform(collision);
}
/// <summary>
/// Description:
/// Built-in Unity function that is called whenever a trigger collider stays inside another collider
/// Input:
/// Collider2D collision
/// return:
/// void (no return)
/// </summary>
/// <param name="collision">The collider that is still in the trigger</param>
private void OnTriggerStay2D(Collider2D collision)
{
MakeAChildOfAttachedTransform(collision);
}
/// <summary>
/// Description:
/// Built-in Unity function that is called whenever a collider exits a trigger collider
/// Input:
/// Collider2D collision
/// return:
/// void (no return)
/// </summary>
/// <param name="collision">The collider that exited the trigger</param>
private void OnTriggerExit2D(Collider2D collision)
{
DeChild(collision);
}
/// <summary>
/// Description:
/// Makes the passed collider a child of the transform that this script is attached to
/// Works only for the player character but could be expanded to work for non-player characters
/// Input:
/// Collider2D collision
/// Return:
/// void (no return)
/// </summary>
/// <param name="collision">The collision to make no longer a child</param>
private void DeChild(Collider2D collision)
{
if (collision.tag == "Player")
{
collision.gameObject.transform.SetParent(null);
}
}
/// <summary>
/// Description:
/// Makes the passed collider a child of the transform that this script is attached to
/// Input:
/// Collider2D collision
/// Return:
/// void (no return)
/// </summary>
/// <param name="collision">The collision whos transform will be childed</param>
private void MakeAChildOfAttachedTransform(Collider2D collision)
{
if (collision.tag == "Player")
{
collision.gameObject.transform.SetParent(transform);
}
}
}
public class Teleporter : MonoBehaviour
{
public GameObject teleportPoint;
public GameObject Player;
private void OnTriggerEnter2D(Collider2D collision)
{
if (teleportPoint != null) { Player.transform.position = new Vector2 (teleportPoint.transform.position.x, teleportPoint.transform.position.y+1); }
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour
{
public GameObject Spawnitem;
void OnEnable()
{
if (Spawnitem != null)
{
Instantiate(Spawnitem, transform.position, Quaternion.identity, null);
}
}
I don't know why I do this to myself, I guess I just like buyer's remorse or something, but I find myself googling and reading lots of articles on best beginner game engines
In other news Steam recommended me this software from 2015 called Crocotile that is a low-poly 3d editor with tilemaps. The reviews are good and say it's sort of the Aesprite of 3d, like if you want to dip your toes in 3d art without learning Blender and Maya and serious shit, then this is a good way to quickly and easily make low-poly 3d assets that you can export and use in your Unity/Godot/GameMaker/whatever game.
Ok got it working by using the OnTriggerEnter2D(Collider2D collision) methods instead that my other scripts use:
<snip>
Question: What's the point of col? It's set as col.isTrigger = true at start, but then never used again?
Ughhh, I just can't even start on this stupid project and it's driving me a bit nuts.
The base template they provided for the platformer just feels BAD. I hate the camera, I hate the player movement, I hate the jumping and sounds, I hate the tilemap collision. It also feels a bit input laggy.
Any suggestions on modifying this base template to make the core feel better to actually make a game out of it?
Also I'm guessing for buttons you step on, you'd just put an invisible collider trigger a bit above the button and on triggerenter you'd have it swap sprites to a pressed button (maybe also instantiate a transition animation and sound effect) and then trigger whatever you want (like a platform moving) and then on colliderexit swap it back to the original sprite with the transition effect? Need to look up how to code a sprite transition. Or maybe you just swap between two different game objects that you plug in beforehand in the inspector? (pressed button, non-pressed button).
GreatSage, any idea what is going on here? I used your on/off trigger to enable a crate spawner. On the first enable it spawns a normal crate, but then every enable afterwards it spawns a really thin crate wtf?
Well, switching it to the prefab crate instead of some random crate in the map seems to fix it so who knows, but it's fine.
private void HandleMovementInput()
{
Vector2 movementForce = Vector2.zero;
if (Mathf.Abs(horizontalMovementInput) > 0 && state != PlayerState.Dead)
{
movementForce = transform.right * movementSpeed * horizontalMovementInput;
}
MovePlayer(movementForce);
}
private void MovePlayer(Vector2 movementForce)
{
if (grounded && !jumping)
{
float horizontalVelocity = movementForce.x;
float verticalVelocity = 0;
playerRigidbody.velocity = new Vector2(horizontalVelocity, verticalVelocity);
}
else
{
float horizontalVelocity = movementForce.x;
float verticalVelocity = playerRigidbody.velocity.y;
playerRigidbody.velocity = new Vector2(horizontalVelocity, verticalVelocity);
}
if (playerRigidbody.velocity.y > 0)
{
foreach (string layerName in passThroughLayers)
{
Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("Player"), LayerMask.NameToLayer(layerName), true);
}
}
else
{
foreach (string layerName in passThroughLayers)
{
Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("Player"), LayerMask.NameToLayer(layerName), false);
}
}
}
Problem is, even if I could write some code that said "when colliding with a conveyer belt tag, turn off that one line", now I can't move my player because I removed the velocity entirely and all I can do is move while jumping.
I feel like there has to be a good solution for this that says when colliding with conveyer tag, don't use that line of code, instead use "______" to move left/right?
if (col.ground =="conveyor") => rb.setvelocity((input.x * moveSpeed)+conveyor.velocity, rb.velocity.y);
Also if there is stuff like this for every genre to turn Unity into Super Mario Maker of all genres that's crazy and completely changes the idea of game making I had in my head. It does feel like cheating though.
So, at the end of the day and a lot of excuses and distractions, the truth is I just don't know how to make a fun 2d platformer :'(
Like you tell me to make a shmup, I just try to make fun & challenging bullet patterns to dodge through with some neat gfx effects, make an adventure game, come up with a story and some dialogue and item based puzzles, horror game, make some spookiness or scares, rpg make a story, some towns/dungeons and a battle system.
But like "place down platforms and dangerous things in a way that is 'fun'" and just...no idea. Same with puzzles. If I make a door that is locked and you have to push a crate on a button, is that fun or is that tedious busywork?
And then I'm like here are all the things I don't know how to do to execute that:
Room #2 - Screen shakes
Room #3 - Would want flashing red lights like an alarm, don't know how to do colored lighting
Room #6 - Don't know how to do water motions of something moving in water and not just in a straight waypoint move line, also camera changing tracking to follow robo downstream
Room #7 - Don't know how to do particles to show splash
All three levels are clearable.
That being said I've decided to throw it all in the fire and start from scratch. No template, no Corgi engine, just new project, make my own character movement, camera movement, game manager, UI manager, use my own art assets from the start for tiles/objects/player.
I haven't written any camera script stuff, but how hard is a camera controller that just follows a target's transform position? I think the game manager script will be the toughest bit for me to learn how to make, but conceptually I understand it, so maybe not.
private void OnTriggerStay2D(Collider2D collision)
{
if(collision.CompareTag("Conveyor"))
{
private SurfaceEffector2D col;
col = collision.GetComponent<SurfaceEffector2D>();
rb.velocity = new Vector2 ((dirX * movementSpeed) + col.velocity, rb.velocity.y);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class testbelt : MonoBehaviour
{
// We will need a list of items on the belt. Generic list collections work best for dynamically sizing arrays imo
public List<GameObject> objsOnBelt;
//you can adjust the speed using the float speed. If you want the belt to push right left use a negative number.
public float speed;
// Use this for initialization
void Start()
{
//Best to initialize the list. I find that objects with scripts added dynamically through code don't always intalize lists
objsOnBelt = new List<GameObject>();
}
// Update is called once per frame
void Update()
{
if (objsOnBelt.Count != 0)
{
//We no longer need a bool we can simple see if the list is empty
for (int i = 0; i < objsOnBelt.Count; i++)
{
Debug.Log("MovingPlayer");
objsOnBelt[i].transform.position += transform.right * (speed * Time.deltaTime);
}
}
}
void OnTriggerEnter2D(Collider2D col)
{
//Enter is good for a player detetion because we just need when the player first enters the collider.
// The player will need a rigidbody2d for this detection to work.
if (col.gameObject.tag == "Player" || col.gameObject.tag == "ConveyorObj")
{
// "Player" is a standard tag in the editor you can change your player's tag in the drop down.
// Create a new tag for objects that can react to the conveyor.
Debug.Log("Player in the coveyor");
// Remeber to always delete uncessary debus before building.
objsOnBelt.Add(col.gameObject);
}
}
void OnTriggerExit2D(Collider2D col)
{
if (col.gameObject.tag == "Player" || col.gameObject.tag == "ConveyorObj")
{
// "Player" is a standard tag in the editor you can change your player's tag in the drop down.
Debug.Log("Player left the coveyor");
// Remeber to always delete uncessary debus before building.
objsOnBelt.Remove(col.gameObject);
}
}
private void UpdateMovement()
{
dirX = Input.GetAxisRaw("Horizontal");
if (OnConvey)
{
rb.velocity = new Vector2((dirX * movementSpeed) + suf.speed, rb.velocity.y);
}
else
{
rb.velocity = new Vector2(dirX * movementSpeed, rb.velocity.y);
}
if (Input.GetButtonDown("Jump") && isGrounded())
{
rb.velocity = new Vector2(rb.velocity.x, jumpStrength);
}
}
if (OnConvey && Input.GetButtonDown("Jump") && isGrounded())
{
rb.velocity = new Vector2(rb.velocity.x, jumpStrength);
StartCoroutine(AffectJump());
}
else
{
if (Input.GetButtonDown("Jump") && isGrounded())
{
rb.velocity = new Vector2(rb.velocity.x, jumpStrength);
}
}
IEnumerator AffectJump()
{
Debug.Log("Is Grounded: " + isGrounded());
while (!isGrounded())
{
Debug.Log("Getting here");
rb.velocity = new Vector2(rb.velocity.x, jumpStrength);
}
yield break;
}
learning how and why to make most things private and used [serializefield] instead of public
Although the more I google this, the more it seems like conveyer belts for characters in 2d games are something that's just inherently a problematic issue in Unity?
https://forum.unity.com/threads/player-controller-unity-2d-character-script-not-working-with-surface-effector-2d.974505/#post-6336327
I've googled for days and there's not a single video/website on how to add a simple mario conveyer belt for a 2d game that the player can ride. It's kind of crazy since conveyers are like really basic platforming tools.
Conceptually the only way I think you could get around this would be to either:
A) Lock your player's jump in once you leap on the first frame, so you can't adjust any movement mid-air.
B) Somehow tell it to keep running with the conveyor belt speed added to your velocity for an extra second or two?
player.velocity.X = CheckModifiers(Input.getaxis("Horizontal"));
rb.velocity = Vector2(player.velocity.x, player.velocity.y);
float CheckModifiers(float currentVal)
{
newval = currentVal;
//stuff that modifies val
return(newVal);
}
bool hasEffect;
float moveSpeed=10f;
float conveyorTimer;
float conveyorEffect=5f;
void OnCollisionEnter(col other)
{
if (other.tag.name=="Conveyor") { ConveyorEffect(100); }
}
void OnCollisionStay(col other)
{
if (other.tag.name=="Conveyor") { ConveyorEffect(100); }
}
void ConveyorEffect(float duration)
{
if (!hasEffect) { Invoke("EffectsTimer", 0.1f, 0.1f); hasEffect=true; }
conveyorTimer=duration;
}
void EffectsTimer()
{
if(!hasEffect) { CancelInvoke(); return; }
else
{
bool endCheck=false;
// all your effects checks
if (conveyorTimer>0) { conveyorTimer-=duration; } else { endCheck=true; }
if (endcheck) { hasEffect=false; }
}
}
float GetPlayerXVelocity(float baseline)
{
playerX = Input.Getaxis("Horizontal") * baseline * Time.deltatime; // or whatever
if (conveyorTimer>0) { playerX += conveyorEffect; }
return(playerX);
}
void DoMove()
{
rb.velocity = Vector2(GetPlayerXVelocity(movespeed), rb.velocity.y);
}
float GetPlayerXVelocity(float baseline)
{
playerX = Input.Getaxis("Horizontal") * baseline * Time.deltatime; // or whatever
if (conveyorTimer>0) { playerX += conveyorEffect; }
if (conveyorTimer2>0) { playerX += conveyorEffect2; }
return(playerX);
}
void ConveyorEffect(float duration)
{
Debug.Log("Getting Here4");
if (!hasEffect) { Invoke("EffectsTimer", 0.1f); hasEffect = true; }
conveyorTimer = duration;
}
void EffectsTimer()
{
if (!hasEffect) { CancelInvoke(); return; }
else
{
Debug.Log("Getting Here5");
bool endCheck = false;
// all your effects checks
if (conveyorTimer > 0) { Debug.Log("Getting Here6"); conveyorTimer -= duration; }
else { Debug.Log("Getting Here7"); endCheck = true; }
if (endCheck) { Debug.Log("Getting Here8"); hasEffect = false; }
}
}
It compiles and runs but still not getting the "getting here 7" meaning the timer is never = or <0 even when off the belt.
if (conveyorTimer > 0) { Debug.Log("Getting Here6"); conveyorTimer -= duration; }should probably be
if (conveyorTimer > 0) { conveyorTimer -= 1; Debug.Log("Getting Here6, and timer is: " + conveyorTimer); }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
#region Variables
private Rigidbody2D rb;
private SpriteRenderer sprite;
private BoxCollider2D coll;
private Animator anim;
private float dirX = 0f;
bool hasEffect;
float conveyorTimer;
float conveyorEffect = 5f;
float duration;
[SerializeField] private LayerMask jumpableGround;
// Gets movement speed & jump strength
[SerializeField] private float movementSpeed = 7f;
[SerializeField] private float jumpStrength = 14f;
public GameObject Convey = null;
private SurfaceEffector2D suf;
private enum MovementState { idle, running, jumping, falling }
private MovementState state = MovementState.idle;
#endregion
/// <summary>
/// Gets and assigns the rigidbody, animator and sprite to local variables
/// </summary>
private void Start()
{
Debug.Log("Start");
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sprite = GetComponent<SpriteRenderer>();
coll = GetComponent<BoxCollider2D>();
if (Convey != null) {
suf = Convey.GetComponent<SurfaceEffector2D>();
}
}
/// <summary>
/// Updates Movement & Animation State
/// </summary>
private void Update()
{
UpdateMovement();
UpdateAnimationState();
Debug.Log("Conveyor Time: " + conveyorTimer);
}
/// <summary>
/// Gets horizontal axis movement and applies it with movement speed to be the new x-axis velocity
/// Gets jump and assigns y-axis velocity based on jump strength while still using existing movement speed from last frame
/// </summary>
private void UpdateMovement()
{
GetPlayerXVelocity();
rb.velocity = new Vector2(dirX, rb.velocity.y);
if (Input.GetButtonDown("Jump") && isGrounded())
{
rb.velocity = new Vector2(rb.velocity.x, jumpStrength);
}
}
float GetPlayerXVelocity()
{
dirX = Input.GetAxisRaw("Horizontal") * movementSpeed;
if (conveyorTimer > 0) { dirX += conveyorEffect; }
return (dirX);
}
/// <summary>
/// Updates animation based on if running or idle and flips sprite based on horizontal direction
/// </summary>
private void UpdateAnimationState()
{
MovementState state;
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0)
{
state = MovementState.running;
sprite.flipX = true;
}
else
{
state = MovementState.idle; ;
}
if (rb.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rb.velocity.y < -.1f)
{
state = MovementState.falling;
}
anim.SetInteger("State", (int)state);
}
/// <summary>
/// Does Boxcast .1f down and returns true or false if overlapping jumpableGround layer
/// </summary>
/// <returns></returns>
private bool isGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Conveyer")) { Debug.Log("Starting Conveyer Effect"); ConveyorEffect(10); }
else conveyorEffect = 0f;
}
void OnCollisionStay2D(Collision2D other)
{
if (other.gameObject.CompareTag("Conveyer")) { ConveyorEffect(10); }
else conveyorEffect = 0f;
}
void ConveyorEffect(float duration)
{
Debug.Log("Getting Here4");
if (!hasEffect)
{ InvokeRepeating("EffectsTimer", 0, .1f);
hasEffect = true;
}
conveyorTimer = duration;
}
void EffectsTimer()
{
if (!hasEffect) { CancelInvoke(); return; }
else
{
Debug.Log("Getting Here5");
bool endCheck = false;
// all your effects checks
if (conveyorTimer > 0) { Debug.Log("Getting Here6");
conveyorTimer--;
conveyorEffect = 5;
}
else { Debug.Log("Getting Here7"); endCheck = true; }
if (endCheck) { Debug.Log("Getting Here8"); hasEffect = false; conveyorEffect = 0; }
}
}
}
void EffectsTimer()
{
if (!hasEffect) { CancelInvoke(); return; }
else
{
Debug.Log("Getting Here5");
bool endCheck = false;
bool Jumped = false;
bool Airborne = false;
bool Landed = false;
// all your effects checks
if (conveyorTimer > 0 && !Landed) { Debug.Log("Getting Here6");
if (rb.velocity.y != 0)
{
Debug.Log("Jumped!");
Jumped = true;
}
if (Jumped == true && !isGrounded())
{
Debug.Log("Airborne!");
Airborne = true;
Jumped = false;
}
if (isGrounded() && Airborne == true)
{
Debug.Log("Landed!");
Landed = true;
Airborne = false;
}
conveyorEffect = 5;
conveyorTimer--;
}
else { Debug.Log("Getting Here7"); endCheck = true; }
if (endCheck) { Debug.Log("Getting Here8"); hasEffect = false; conveyorEffect = 0; }
}
}
When I jump against the belt it's tougher because of the force = good
When I jump with the belt I get extra distance because of the force = good
When I'm on the belt I get pushed in the direction = good
When I'm off the belt I get normal movement = good
But...when I jump against the belt and turn in mid-air towards the belt I go flying that way.
Btw, was thinking and similar to the "after airborne if I collide with an object -> cancel momentum timer invoke" idea above,
If you did an "after airborne if getRawInput on horizontal axis and it's in the opposite direction from the direction when I jumped -> cancel momentum timer invoke", that should basically let you control your momentum leap mid-air by pressing back, which seems...ok? And if you're jumping against the momentum you'll just fall down instead of being pushed back with momentum which seems good?
It's pretty good! I'm very happy with it and it's a good start. Lots of stuff I can clean up and do with the first stage. It's also pretty lengthy. Not sure how that'll work for stuff like Itch.io play in window games if they're actually more than like a 5 min game.
Like I wanted to have signs that you activate by pressing UP. And I figured I'd just use getinputbutton like I do for jump or getrawverticalaxis and if axis goes > .1f or getinputkey("vertical.up") or ("up") or some fucking thing but after an hour of googling and reading documentation I never figured it out how to just check if they are pressing up on a sign. So now the signs just auto play when you stand in them :|
if (input.getaxisraw("Vertical") > 0)
it'll be something likeCode: [Select]if (input.getaxisraw("Vertical") > 0)
I'm pretty sure; might be easier to do a button check anyway though? (IIRC SMW does the infoboxes with jump)
For the 'still has some momentum after leaving a conveyor without jumping' thing, presumably your grounded check has an if (floortag=conveyor) { doconveyorstuff(); } check? because you can zero out any conveyor stuff if grounded and not on a conveyor pretty safely I'd think, as that's basically how friction works anyway.
private bool isConveyor()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, Convey);
Debug.Log("OnConvey");
}
private bool isGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
if (isGrounded() && !isConveyor())
{ conveyorEffect = 0; }
if (isGrounded() && isConveyor())
{ ConveyorEffect(20); }
void EffectsTimer()
{
if (!hasEffect) { CancelInvoke(); return; }
else
{
Debug.Log("Getting Here5");
bool endCheck = false;
bool Airborne = false;
bool Landed = false;
// all your effects checks
if (conveyorTimer > 0 && !Landed)
{
Debug.Log("Getting Here6");
if (!isGrounded())
{
Debug.Log("Airborne!");
Airborne = true;
}
if (isGrounded() && Airborne && !isConveyor())
{
Debug.Log("Landed!");
Landed = true;
Airborne = false;
}
conveyorEffect = 5;
conveyorTimer--;
}
else
{
conveyorTimer = 0;
conveyorEffect = 0;
Debug.Log("Getting Here7"); endCheck = true;
}
if (endCheck) { Debug.Log("Getting Here8"); hasEffect = false; conveyorEffect = 0; }
}
}
(https://i.imgur.com/PmKELHal.jpg)
(https://i.imgur.com/rD21lMu.jpg)
Some WIP shots, using placeholder main guy for now and those are placeholder trees until I make some tree tiles
if (!isGrounded())
{
Debug.Log("Airborne!");
Airborne = true;
}
void EffectsTimer()
{
if (!hasEffect) { CancelInvoke(); return; }
else
{
bool endCheck = false;
bool Landed = false;
if (isGrounded() && !isConveyor())
{
Debug.Log("Landed!");
Landed = true;
}
if (conveyorTimer > 0 && !Landed)
{
if (!isGrounded())
{
Debug.Log("Airborne!");
}
conveyorEffect = 5;
conveyorTimer--;
}
else
{
conveyorTimer = 0;
conveyorEffect = 0;
endCheck = true;
}
if (endCheck) { hasEffect = false; conveyorEffect = 0; }
}
}
private void Update()
{
UpdateMovement();
if (Input.GetAxisRaw("Horizontal") != 0 || isGrounded())
{ UpdateAnimationState(); }
}
public class Switch : MonoBehaviour
{
public bool ON = false;
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{ ON = !ON; }
}
public bool CheckOn()
{ if (ON == true) { return true; } else return false; }
}
public class BeltScript : MonoBehaviour
{
[SerializeField] private bool On;
[SerializeField] private GameObject OnOffSwitch = null;
[SerializeField] private GameObject ReverseSwitch = null;
private Switch OnOff;
private Animator anim;
private SurfaceEffector2D suf;
private SpriteRenderer sprite;
private float beltSpeed;
// Start is called before the first frame update
void Start()
{
suf = GetComponent<SurfaceEffector2D>();
anim = GetComponent<Animator>();
sprite = GetComponent<SpriteRenderer>();
OnOff = GetComponent<Switch>();
beltSpeed = suf.speed;
}
// Update is called once per frame
void Update()
{
Debug.Log("On = " + OnOff.CheckOn());
if (OnOff.CheckOn())
{
suf.speed = beltSpeed;
if (beltSpeed < .1f)
{ sprite.flipX = true; }
anim.enabled = true;
}
if (!OnOff.CheckOn())
{
suf.speed = 0;
anim.enabled = false;
} }}
Have a weird glitch where somehow my character gets pulled up the left vertical side into the air upon contact with the surface collider. Despite the surface collider having no effect on anything else.
Pretty sure this is because I don't mess with y.velocity and it's basically on default RB which is what 2d surface effect effects.
I'm making AN ENTIRE ROOM OF NOTHING BUT CONVEYOR BELT PLATFORMING in order to justify all this time spent on this logic problem.
Quick question,
If I want switches and stuff to only activate when colliding with feet, do I basically make a gameobject and attach it to the player called "feet" with a feet box collider and then tag it feet and use that with these objects like standing on buttons? (and put their collision boxes off the ground a bit so running into it won't trigger with ground feet)
Oh and for final questions at this point, this is what I've got:
1. I'm being real good at keeping everything private and [SerializeField], but the methods I'm calling in other scripts I'm using public void method(). Is there a better way I should be doing this to keep them private and not introduce bugs?
2. One of the things I haven't tried to do yet since I haven't needed it is write a script of something that keeps track of stuff between stages/deaths. Like your score and lives if you use lives (this game isn't going to use lives so it's just restart scene on death, I like platformers these days with no life counters and just a lot of checkpoints).
Does doing this have something to do with don'tdestroyonload? Because I googled that to stop the stage BGM from starting over on death and I use that and it basically keeps a separate instance going with the music in it that is separate from the scene.
Or do you put all that in the gamemanager and just have the gamemanager not be destroyed on load so it can carry over these things? I feel like this will be helpful to learn for creating inventory systems that carry between scenes/stages. I.e. I want to know if my character picked up a Jetpack in the previous stage and should now be flying around.
I'm making AN ENTIRE ROOM OF NOTHING BUT CONVEYOR BELT PLATFORMING in order to justify all this time spent on this logic problem.
:lol
I'm pretty sure this is the background info on Sonic 1s Marble Zone too
But yeah the Unity folder was like 60,000 files already. Was too intense for my old HDD :lol
Been looking into statics.
For my audiomanager which I want so the music keeps its spot on scene reset on death, for changing BGMs per level/area/scene, would it make the most sense to have my audiomanager gameobject basically loaded with the entire game soundtrack and all the tracks and then I could put a public method on it called "ChangeTrack(track name)"
And then in any other script I can just tell it to ChangeTrack(put track name here) and then it will switch currentBGM private variable in the static to whatever track name is and play it?
I'm not sure where I would put code to call this, maybe a script on an object called [Scene_X_Start_Object] which has a script for that one scene and calls on start to change track and set whatever else for the scene?
The letter by letter (array of characters displayed one at a time) with goofy sounds for each letter and a background & portrait of the character talking is pretty classic and flexible, so if for some reason I can't use the dialogue system I bought I may try this:
public class CurrentCheckPointTrack : MonoBehaviour
{
// Start is called before the first frame update
[SerializeField] private Checkpoint chk = null;
public void Start()
{
chk = null;
}
public void AddCheckpoint(Checkpoint talky)
{
chk = talky;
Debug.Log("new checkpoint spot = " + chk.transform.position.x + chk.transform.position.y);
}
public Vector2 GetCheckpoint()
{
if (chk != null)
{
return new Vector2(chk.transform.position.x, chk.transform.position.y);
}
else
{
Debug.Log("No Checkpointset");
return new Vector2(0, 0);
}
}
}
public static class CheckpointTracker
{
// The most recently activated checkpoint
public static Checkpoint currentCheckpoint = null;
}
public class Checkpoint : MonoBehaviour
{
public Transform respawnLocation;
public GameObject checkpointActivationEffect;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Player")
{
if (CheckpointTracker.currentCheckpoint != this && checkpointActivationEffect != null)
{
Instantiate(checkpointActivationEffect, transform.position, Quaternion.identity, null);
}
// Set current checkpoint to this and set up its animation
CheckpointTracker.currentCheckpoint = this;
}
}
}
public class Keep_Music_On_Death : MonoBehaviour
{
static Keep_Music_On_Death instance = null;
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
}
public class TacosTesting : MonoBehaviour
{
static TacosTesting instance = null;
public static int numbertest = 0;
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
public int ReturnNumber()
{
return numbertest;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class TacosTesting : MonoBehaviour
{
static TacosTesting instance = null;
public static int numbertest = 0;
public GameObject PauseScreen;
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
private void Update()
{
if (SceneManager.GetActiveScene().buildIndex == 0)
{ numbertest = 0; }
if (SceneManager.GetActiveScene().buildIndex == 0)
{ Time.timeScale = 1; PauseScreen.SetActive(false); }
if (SceneManager.GetActiveScene().buildIndex != 0 && SceneManager.GetActiveScene().buildIndex != 3 && Input.GetButton("Cancel"))
{ Time.timeScale = 0; PauseScreen.SetActive(true); }
}
public int ReturnNumber()
{
return numbertest;
}
}
Ok, fixed it by instead of putting a drag & drop serialized field with the player in it I tried just FINDING the player and it works now. Who the fuck knows why, but I'll take it
I just switched the serializedfield game object player1 and then p1p grabbined from the serializedfield gameobject player1.getcomponent<transform>(); to
p1p = GameObject.FindWithTag("Player").transform;
Also regarding statics and stuff I don't really understand, now that I have a pause menu and can go back to the main menu, how do I tell this static to go away.
-When I try to call new INT Burrito = TacosTest.ReturnNumber(); it doesn't work. So I don't know how to do methods in a static script from another script.
static TacosTesting instance = null;
Ok, fixed it by instead of putting a drag & drop serialized field with the player in it I tried just FINDING the player and it works now. Who the fuck knows why, but I'll take it
I just switched the serializedfield game object player1 and then p1p grabbined from the serializedfield gameobject player1.getcomponent<transform>(); to
p1p = GameObject.FindWithTag("Player").transform;
I'm gonna guess your respawn code is like the 'teleporter' from The Prestige, and you're not actually moving the current player somewhere, you're destroying them and then creating a new copy somewhere else?
Because that'll be why your cached reference doesn't work as a pointer anymore - its actually a completely different hugh jackman.
Findwithtag is actually a kinda terrible way to get pointers, but if it works it works - either using your original pointer reference and disabling it, moving it, reenabling it or grabbing the pointer reference at reinstantition would be better ways of doing this, but - no shade - you're at the point where you're learning to get shit working, so imo don't sweat the 'proper ways' until youre comfortable with ways that work.Also regarding statics and stuff I don't really understand, now that I have a pause menu and can go back to the main menu, how do I tell this static to go away.
It seems like you're leaning more into singleton use, but yeah, the point is it never goes away, you want to handle whatever it exists for on it.
So if you want a different track per level, you're better off having an audiomanager singleton that has ALL the music on it, and then loads up the next tune when the next levels loaded, rather than having an individual music track object per level (or at worst, if you do have a single object for music per level, they are triggered by your singleton rather than acting independtly of each other).
Doing it this way lets you do cool stuff like cross fade from one track to another while the levels loading and shit.-When I try to call new INT Burrito = TacosTest.ReturnNumber(); it doesn't work. So I don't know how to do methods in a static script from another script.
So the important bit of your code here that I think you're overlooking is this bit;Code: [Select]static TacosTesting instance = null;
Tacostesting is your class name, the thing that actually holds that code and the variables is a variable of <T> (type) TacosTesting named instance.
So you need to find that - luckily as its static, it should be as easy as
TacosTest.instance.ReturnNumber();
public static int numbertest
private int numbertest;
public void UpdateScore()
{
numbertest++;
}
public int GetScore()
{
return instance.numbertest;
}
public class Teleporter : MonoBehaviour
{
public GameObject teleportPoint;
private void OnTriggerEnter2D(Collider2D collision)
{
if (teleportPoint != null)
{
collision.gameObject.transform.position = teleportPoint.transform.position;
}
}
}
private void UpdateAnimationState()
{
MovementState state;
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0)
{
state = MovementState.running;
sprite.flipX = true;
}
else
{
state = MovementState.idle; ;
}
if (rb.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rb.velocity.y < -.1f)
{
state = MovementState.falling;
}
anim.SetInteger("State", (int)state);
}
public class Teleporter : MonoBehaviour
{
public GameObject teleportPoint;
private Rigidbody2D rb;
private void OnTriggerEnter2D(Collider2D collision)
{
if (teleportPoint != null)
{
rb = collision.GetComponent<Rigidbody2D>();
rb.bodyType = RigidbodyType2D.Static;
collision.gameObject.transform.position = teleportPoint.transform.position;
rb.bodyType = RigidbodyType2D.Dynamic;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Basic switch can jump on if you put a trigger on top
/// If trigger hits feet, switch is switched
/// This trigger flips direction of receiving object (belt in this case) if it has a flip direction method
/// </summary>
public class ReverseSwitch : MonoBehaviour
{
[SerializeField] private GameObject[] Belt;
private BasicConScript[] BeltScript;
private int currentIndex = 0;
private void Start()
{
if (Belt != null)
{
while (currentIndex < Belt.Length)
{
BeltScript[currentIndex] = Belt[currentIndex].GetComponent<BasicConScript>();
currentIndex++;
}
currentIndex = 0;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Feet"))
{
while (currentIndex < Belt.Length)
{
BeltScript[currentIndex].FlipDirection();
currentIndex++;
}
}
}
}
I'm trying to add multiple conveyor belts to my reverse switch so a single switch stomp reverses a bunch of belts instead of just one. First time trying to use arrays and not sure why this isn't working? It says null error that the method calls are "object reference not set to an instance of an object"
What am I missing?
for (int i = 0; i < BeltScript.length; i++)
{
BeltScript[i].FlipDirection();
}
Making games is a lot of work :doge
Wait, do I not need to call getcomponent<>(); on a gameobject to get its script when calling a method within a script on it?
I thought I had to get the script as a variable and call the method from that variable.
Making games is a lot of work :doge
Wait, do I not need to call getcomponent<>(); on a gameobject to get its script when calling a method within a script on it?
I thought I had to get the script as a variable and call the method from that variable.
if your array was of Type Gameobject, you might have to, but its of Type BasicConScript (which is the class I assume contains that method) so you can pretty much assume an array of component<BasicConScript> definitely has component<BasicConScript>
Making games is a lot of work :doge
:P
So worth it tho :lawd
I'm trying to add multiple conveyor belts to my reverse switch so a single switch stomp reverses a bunch of belts instead of just one. First time trying to use arrays and not sure why this isn't working? It says null error that the method calls are "object reference not set to an instance of an object"
What am I missing?
I dunno man, I'm afraid I can't debug this for ya from this info.
what I would say though is it seems a little overcomplicated; couldn't you do something like:Code: [Select]for (int i = 0; i < BeltScript.length; i++)
{
BeltScript[i].FlipDirection();
}
[SerializeField] private GameObject[] Belt = null;
private BasicConScript BeltS1;
private BasicConScript BeltS2;
private int i = 0;
private void Start()
{
BeltS1 = Belt[i].GetComponent<BasicConScript>();
i++;
BeltS2 = Belt[i].GetComponent<BasicConScript>();
i = 0;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Feet"))
{
BeltS1.FlipDirection();
BeltS2.FlipDirection();
}
}
private T[] AddElementToArray<T>(T[] array, T element) {
T[] newArray = new T[array.Length + 1];
int i;
for (i = 0; i < array.Length; i++) {
newArray[i] = array[i];
}
newArray[i] = element;
return newArray;
}
public class ReverseSwitchArray : MonoBehaviour
{
[SerializeField] private GameObject[] Belt = null;
private BasicConScript[] BeltS;
private void Start()
{
BeltS = new BasicConScript[Belt.Length];
for (int i = 0; i < Belt.Length; i++)
{
BeltS[i] = Belt[i].GetComponent<BasicConScript>();
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Feet"))
{
for (int j = 0; j < Belt.Length; j++)
{
BeltS[j].FlipDirection();
}
}
}
I like that I'm at the point where if I can think up something in my head I can program it to happen.
Oh, is there any easy way to record gameplay and then play it back as a cutscene?
Another question I have for Unity/C#, when do InvokeRepeating, is the time based on something that will be the same across hardware? Or will it be one of those things where at 120fps it'll fire off the invoke method more often than someone playing it at 30fps in the same amount of time? I'm using InvokeRepeating on my spawner to spawn bombs for my conveyor belt boss. Wondering if this is problematic and I should tie it to a time.deltatime thing instead?
Finally googled some stuff on game dev creative block and viola there's a lot of very helpful tips out there because this is not a unique thing.
Best advice I found was get off social media and make a small shitty game in a day or two based on one idea whether it's good or bad, because you can't get good at stuff unless you make some sucky things first and just getting something done is motivating. Gonna try that out to get motivated again.
Finally googled some stuff on game dev creative block and viola there's a lot of very helpful tips out there because this is not a unique thing.
Best advice I found was get off social media and make a small shitty game in a day or two based on one idea whether it's good or bad, because you can't get good at stuff unless you make some sucky things first and just getting something done is motivating. Gonna try that out to get motivated again.
Yeah, gamejams are fun (and if you wanna do one just go to itch, they have like, 50 a fucking week lol) but I always lose focus on personal projects and either end up just noodling or abandoning them
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPC_Movement : MonoBehaviour
{
[SerializeField] private float MoveSpeed;
private Rigidbody2D rb;
private int Direction;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
InvokeRepeating("WaitandTurn", 0.1f, 3f);
}
// Update is called once per frame
void Update()
{
Movement();
}
private void DecideDirection()
{
Direction = Random.Range(0, 3);
Debug.Log("Direction Code =" + Direction);
}
private void WaitandTurn()
{
DecideDirection();
}
private void Movement()
{
if (Direction == 0)
{
rb.velocity = new Vector2(0, MoveSpeed);
}
else if (Direction == 1)
{
rb.velocity = new Vector2(0, -MoveSpeed);
}
else if (Direction == 2)
{
rb.velocity = new Vector2(MoveSpeed, 0);
}
else if (Direction == 3)
{
rb.velocity = new Vector2(-MoveSpeed, 0);
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
Debug.Log("Collision!");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This makes an object move randomly in a set of directions, with some random time delay in between each decision
/// </summary>
public class Wanderer : MonoBehaviour
{
internal Transform thisTransform;
public Animator animator;
// The movement speed of the object
public float moveSpeed = 0.2f;
// A minimum and maximum time delay for taking a decision, choosing a direction to move in
public Vector2 decisionTime = new Vector2(1, 4);
internal float decisionTimeCount = 0;
// The possible directions that the object can move int, right, left, up, down, and zero for staying in place. I added zero twice to give a bigger chance if it happening than other directions
internal Vector3[] moveDirections = new Vector3[] { Vector3.right, Vector3.left, Vector3.up, Vector3.down, Vector3.zero, Vector3.zero };
internal int currentMoveDirection;
// Use this for initialization
void Start()
{
// Cache the transform for quicker access
thisTransform = this.transform;
// Set a random time delay for taking a decision ( changing direction,or standing in place for a while )
decisionTimeCount = Random.Range(decisionTime.x, decisionTime.y);
// Choose a movement direction, or stay in place
ChooseMoveDirection();
}
// Update is called once per frame
void Update()
{
// Move the object in the chosen direction at the set speed
Vector3 direction = moveDirections[currentMoveDirection];
float xDir = direction.x;
float yDir = direction.y;
thisTransform.position += direction * Time.deltaTime * moveSpeed;
if (animator)
{
animator.SetFloat("MoveX", xDir);
animator.SetFloat("MoveY", yDir);
}
if (decisionTimeCount > 0) decisionTimeCount -= Time.deltaTime;
else
{
// Choose a random time delay for taking a decision ( changing direction, or standing in place for a while )
decisionTimeCount = Random.Range(decisionTime.x, decisionTime.y);
// Choose a movement direction, or stay in place
ChooseMoveDirection();
}
}
void ChooseMoveDirection()
{
// Choose whether to move sideways or up/down
currentMoveDirection = Mathf.FloorToInt(Random.Range(0, moveDirections.Length));
}
public class Movetowards : MonoBehaviour
{
[SerializeField] private float MoveSpeed = 1;
private float DirX = 1;
private float DirY = 1;
private Vector2 TACO;
private void OnEnable()
{
InvokeRepeating("PickSpot", 0, 3f);
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, TACO, Time.deltaTime * MoveSpeed);
Debug.Log("Position Heading to: " + TACO);
}
public void PickSpot()
{
TACO = new Vector2(Random.Range(-2.8f, 3.2f), Random.Range(-1.7f, 2.76f));
}
private void OnCollisionEnter2D(Collision2D collision)
{
TACO = new Vector2(Random.Range(-2.8f, 3.2f), Random.Range(-1.7f, 2.76f));
}
}/code]
private void Update()
{
if (DRIVE)
{
transform.position = new Vector2(transform.position.x * MoveSpeed * Time.deltaTime, transform.position.y);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class UITracker : MonoBehaviour
{
public static UITracker instance = null;
private int Score;
[SerializeField] private GameObject StartUI = null;
[SerializeField] private GameObject EndUI = null;
[SerializeField] private Text Deaths = null;
[SerializeField] private Text EndDeaths = null;
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
private void Start()
{
if (SceneManager.GetActiveScene().buildIndex == 0)
{
Score = 0;
}
}
private void Update()
{
if (SceneManager.GetActiveScene().buildIndex != 1)
{
StartUI.SetActive(true);
EndUI.SetActive(false);
Deaths.text = "Score = " + Score;
}
if (SceneManager.GetActiveScene().buildIndex == 1)
{
StartUI.SetActive(false);
EndUI.SetActive(true);
EndDeaths.text = "Score:" + Score;
}
}
public void AddScore()
{
Score++;
}
public int GetScore()
{
return Score;
}
}
Honestly, man, don't give up. Learning to code just takes time. There will be frustration but figuring out problems like these is also very rewarding, as seen by all the things you have overcome in the thread so far.
I need some help. I've been stuck an hour on trying to figure out how to right a code to move little AI NPC around in random directions.
Nothing works :maf
public void DoSFX(audioclip fx) // call this from any other script by sending it an audioclip; this wouldn't have 3D spatial properties, but youre making a 2d game right?
{
myAudioSource.PlayOneShot(fx); // myaudiosource would be a cached audiosource component reference
}
public void RestartGame() // assign this to your restart button
{
scenemanager.loadscene(currentscene()); // or whatever the command is
}
// public void MainMenu() // can do another version to take them back to menu screen, or can do a next level button, or whatever you want; again, reference this via your UI buttons
It looks like you solved it, but if you have a game manager, you might be best off routing things through your gamemanager?
You have your score values there, but you can also solve your SFX and button action issues with something like;
The button issue was literally just the UI canvas text covering the button. Like the text didn't cover it, but the text rect was double the size with a lot of blank space and the blank space covered the UI button. I guess I could also fix this by making the UI button the child of the text so it sits on top.
[SerializeField] AudioSource SoundEffect
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
DRIVE = true;
SoundEffect.Play();
}
}
[SerializeField] private AudioSource ADD
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("NPCKILLER"))
{
ADD.Play();
Explode();
StartCoroutine("Death");
Destroy(this.gameObject);
}
else
Newwaypoint = new Vector2(Random.Range(-2.8f, 3.2f), Random.Range(-1.7f, 2.76f));
}
The button issue was literally just the UI canvas text covering the button. Like the text didn't cover it, but the text rect was double the size with a lot of blank space and the blank space covered the UI button. I guess I could also fix this by making the UI button the child of the text so it sits on top.
There's a couple of easier fixes; the generic one, is anything you don't want to block raycasts, put it on the Ignore Raycasts physics layer.
The UI specific one, which is common enough it has its own dedicated fix, is on any UI element, there's a raycast target checkbox on the image component - just uncheck that
Problem #1 - Moving things forward
How do you even quantify an abstract of "the direction you are moving in" when it could be left/right/down/up or any 360 degree direction?
Problem #2 - Multiple Movementsyeah, waypoints would be the solution; you can also check distance from waypoint, then switch up your waypoint to the next one when youre 'close enough' (your gametype would determine when that is, and how smooth you want that transition to be)
Problem #3 - NPC random movementas above; absolute random x/y/z works, but so does having an array of 'valid' waypoints, then randoming array.length (which will 'cluster' based on your placements, not your random results)
Problem #4 - NPC Spawning with screen border collisionSo there's a command called uhhhh getsphererandom or something, which will return a random point on a sphere surface (theres a circle version for 2D too I think) so if you multiply that up so your sphere / circle is bigger thn your playspace, you can spawn things 'off camera' nicely, then waypoint them into the 'scene' - a good way to get a valid 'target' point is just set them to the player position when it spawns (because the players probably moved by the time they get onscreen).
Problem #5 - NPCs spawning on you and instantly killing youAs above, spawning 'offscreen' is super fair.
Problem #6 - Particlesparticles are super fun to play with, watch some tuts!
Problem #7 - SFXyeah, I can't help but feel your NPCs were being destroyed along with their audiosource component, especially as moving it to your spawned VFX solved it.
Problem #8 - UI stuffI think when we were talking about singletons, I have 'UI manager' as a super common usage case for singletons; this kind of thing is why!
Problem #10 - Built it wrong!
I was speedrunning this project so I didn't organize my assets at all or even put my build order scenes in the right order and the main menu was scene 3. Learned the hard way after building it that game always starts on Scene 0! Always put your main menu on Scene 0 lol
Time for me to look up what a raycast is!Its basically a 'laser' that returns info on whatever it hits.
Problem #1 - Moving things forward
How do you even quantify an abstract of "the direction you are moving in" when it could be left/right/down/up or any 360 degree direction?
There's a bunch of premade constants for Vector3 relative positions;
eg Vector3.up = {0,1,0} = 'up'
Vector3.left = {-1,0,0} = 'left'
Vector3.forward = {0,0,1} = 'into the screen'
etc
so you should be able to slap transform.position += vector3.forward * time.deltatime * speed; onto a 'bullet' and it 'just works'
Problem #4 - NPC Spawning with screen border collision
So there's a command called uhhhh getsphererandom or something, which will return a random point on a sphere surface (theres a circle version for 2D too I think) so if you multiply that up so your sphere / circle is bigger thn your playspace, you can spawn things 'off camera' nicely, then waypoint them into the 'scene' - a good way to get a valid 'target' point is just set them to the player position when it spawns (because the players probably moved by the time they get onscreen).
You can also only turn on any 'stay in bounds' checks only when they actually enter bounds.
Problem #5 - NPCs spawning on you and instantly killing you
As above, spawning 'offscreen' is super fair.
Alternatively, have a 'prespawn' animation / VFX / whatever at their spawnpoint before they actually do is also pretty fair.
Problem #7 - SFX
yeah, I can't help but feel your NPCs were being destroyed along with their audiosource component, especially as moving it to your spawned VFX solved it.
IMO putting your clip on your VFX is a nicer solution anyway, as you can clean them both up simultaneously (and also an explosion VFX + SFX prefab is super reusable)
Time for me to look up what a raycast is!
Its basically a 'laser' that returns info on whatever it hits.
Any 'mouse' commands built into Unity, are actually shooting a 'laser' (raycast) from the camera to the mouse pointer, then doing stuff based on what it hits; so if you put a sprite on top of soemthing you want to mouseover, the sprite can actually block it.
Likewise, sometimes you want to manually block a raycast, eg if you have a UI button that clicking on it also shoots a bullet into the world in an FPS UI interaction
Congratulations you shipped a game :rejoice
It's pretty fun to play actually and quite intuitive, no tutorial needed.
Kinda like a reverse Castle Defender type of game as opposed to say Pac-Man.
The level music is also catchy and I dig the atari/retro aesthetic.
Considering you've never made a game before in your life this is pretty impressive.
My first game was literally 2 boxes that collided and some crazy ass trippin' seizure shit in Unity. :doge
Game 3 was way too ambitious but somehow worked. You could scan 3D models with a infared light and those would pop up in a Banjo-like adventure game.
You would have to model shit with clay, for example a chess set was missing a piece so the horse piece asked you to create a new tower piece.
Game 4 was the best gameplay wise and much more streamlined like your game. It was made in Unreal and the laser gun was modded to resemble a super soaker.
You had to shoot the smokers back to the designated smoking areas of the university. It took about 3 months to build and we had 4 people on the team.
Cutting features is part of any software development. You can never create everything you come up with in the time you have.
The key is to retain the things that make the game fun, fake the things that make the game more interesting and cut the things that people don't notice.
Remember, I don't know what your original vision for the game is or was so I can't really tell if Statue Stomping is cut or not.
I always quote Gandalf when new developers I work with complain about running out of time or not having enough time and wanting to spend more time.
"So do I", "and so do all who live to see such times. But that is not for them to decide. All we have to decide is what to do with the time that is given us."
Yeah, I feel like in update transform.position = vector2.right * time.deltatime * speed for my car should work? I was having issues with it. Idk.
Thanks, that's a helpful start. I'm assuming Boxcasting is the same?
My question goes back to your suggestion to raycast & turn for NPC movement. How do you know what direction to raycast the laser out since you won't know what direction the NPC is heading at any time?
Also as an extra cherry on top thing I'd like to save high scores since it's now a survival wave arcade game but I've never messed with that (player preferences, right?) and I'm not sure if I can figure it out in 30 mins or so.
Yeah, I feel like in update transform.position = vector2.right * time.deltatime * speed for my car should work? I was having issues with it. Idk.
just to check youre doing +=, not just = right?
Thanks, that's a helpful start. I'm assuming Boxcasting is the same?
My question goes back to your suggestion to raycast & turn for NPC movement. How do you know what direction to raycast the laser out since you won't know what direction the NPC is heading at any time?
yeah, a boxcast is 'firng' a box object instead of a thin line (so can do shit like calculate if somethng the same size as that box or smaller can fit through a gap for example.
although you dont see the code for it when you use a mouseover command, you define the movement of the ray / box in 3D space by providing the start point and end point and the direction to move / distance to check
Also as an extra cherry on top thing I'd like to save high scores since it's now a survival wave arcade game but I've never messed with that (player preferences, right?) and I'm not sure if I can figure it out in 30 mins or so.
I guess you got this working ok, as its pretty easy if you're only saving an int?
public class ScreenShake : MonoBehaviour
{
public static ScreenShake instance;
Vector3 startPos;
void Awake()
{
instance = this;
}
void Start()
{
startPos = transform.position;
}
IEnumerator Shake()
{
for (int i = 0; i < 3; i++)
{
transform.position = new Vector3(startPos.x + Random.Range(-0.1f, 0.1f), startPos.y + Random.Range(-0.1f, 0.1f), transform.position.z);
yield return new WaitForSeconds(0.05f);
}
transform.position = startPos;
}
public void ShakeMe()
{
StartCoroutine(Shake());
}
}
[SerializeField] private float GodzillaShake = 20f;
private float elapsedTime = 0f;
if (elapsedTime < GodzillaShake)
{
ScreenShake.instance.ShakeMe();
elapsedTime += Time.deltaTime;
}
Still confused on this. Because it's going to be a random spawned NPC heading in a random direction so there is no way to know which direction it is moving in at any time unless I'm missing something? I guess you just raycast 360 around the character and change direction if there's something (which is similar to what I did with using oncolliderenter).
Been playing other people's games in the game jam and giving feedback. This is cool. I've never done a game jam before and everyone playing each other's games and commenting on them has a nice community feel. I think I'll try to do more of these.
Figured out my screen shake issue but need help.
The issue isn't coming from the screen shake, that's why it still shakes for 3 frames on the constant framerate release build. The problem is the timer I'm using to keep calling that 3 frame screen shake. On variable framerate this lasts for like 15-20 seconds, on constant framerate this code lasts for like 1 second?
public AnimationCurve easingCurve;
public WrapMode curveMode;
public float time = 0.1f;
Vector3 currentPos = transform.localPosition;
public Vector3 shakeMagnitude;
IEnumerator CamShakeThing()
{
float i = 0;
float rate = 1 / time;
while (i < 1)
{
i += rate * Time.deltaTime;
transform.localPosition = Vector3.Lerp(shakeMagnitude, currentPos , easingCurve.Evaluate(i));
yield return 0;
}
}
so I can draw in the 'bounciness' of the movement manually)
I found this link among the stuff I read last night about how games uses various camera styles to track:
https://www.gamedeveloper.com/design/scroll-back-the-theory-and-practice-of-cameras-in-side-scrollers
Extremely in-depth, long but informative. I like the idea for platformers of using Super Mario style re-position camera vertically each time you touch the ground from a jump. Also the way Super Mario 1 handles the camera tracking of Mario with a little leeway left/right is genius, would be fun to try to replicate that.
I haven't written any camera script stuff, but how hard is a camera controller that just follows a target's transform position? I think the game manager script will be the toughest bit for me to learn how to make, but conceptually I understand it, so maybe not.
yeah, ez-mode cam control is just making your camera a child of your player object, intermediate is making an invisible object that moves to your player (or a relative position, if you wanted camera 'leading' like your top down shooter) that the camera focuses on, probably with a smoothdamp or lerp and probably in lateupdate after movements resolved so it doesnt seem jerky.
galaxy brain camera is some kind of box focus so you can move in a genre dependent / relevant area without camera movement until you really need it.
https://www.gamedeveloper.com/design/scroll-back-the-theory-and-practice-of-cameras-in-side-scrollers
some good stuff in there for ideas on camera moves.
good job doing all this in like a month Bebpo.
Btw, I was thinking, for hit impact effects can you just use timescale? Like on collision with big sword strike to enemy -> turn timescale from 1.0 -> .7, wait for seconds (1), turn timescale from .7 -> 1.0? That way you hit the enemy with a big hit that kills them and game slowdowns for a second as the enemy explodes and particles fly and then resumes back to normal speed?
Btw, I was thinking, for hit impact effects can you just use timescale? Like on collision with big sword strike to enemy -> turn timescale from 1.0 -> .7, wait for seconds (1), turn timescale from .7 -> 1.0? That way you hit the enemy with a big hit that kills them and game slowdowns for a second as the enemy explodes and particles fly and then resumes back to normal speed?
Zelda style? Yeah, you can totally do that.
If you create your own Time function thats based on... timesincestartup? I think it is? you can have stuff moving at regular speed while everything else is in bullet time too... did we discuss this before? I have a feeling of deja vu talking to you about running realtime shit while the rest of the games timescale is in bullet time...
its pretty easy, you just make two methods to replace time.deltatime calls, one that returns time.deltatime (which will scale) and the other that returns realtime.deltatime (which ignore scaling).
I've used it twice..? I think, one was when they introduced the new UI system all of the things like sliders were using time.deltatime so if you made a timescale=o pause button, all your UI interactions fucking broke :lol
The other was in an RTS type game where I wanted you to be able to pause the game, but still move the camera around manually, and still using deltatime to smooth its movement out
Jetpacks are fun.
Wanna design a small game together bebps? :thinking
I'm thinking small GB size.
Interesting uses. So when you timescale 0 you can’t move the camera around for your RTS example? Could you write an if statement in your camera saying if paused ignore timescale or something?
And UI sliders don’t work on timescale 0? That’s…good to know. I was planning on putting my volume control slider on my pause menu.
camera.transform.position += target.position * movespeed * time.deltatime
type call is going to always return 0, because you're now making time.delatime always return 0, and anything times 0 is always 0Gonna get back to this soon. Had major surgery and been dealing with recovery this week so lost all interest in coding and game making. Gonna try to get motivated and back to it this weekend with something small.
Feels like with coding can develop an aversion when you haven't been doing it for a week or two. Like coding player movement all over again just feels like "ugh, work"
the only artists I know are ex-gfs and I'm not hitting them up for art. So I don't really have anyone to work with.
Jetpacks are fun.
Wanna design a small game together bebps? :thinking
I'm thinking small GB size.
Would love to! As long as you're thinking like finish it in a couple of weeks kind of thing, or at least a prototype with everything done outside needing more stages that can piecemeal add on. Not ready yet to commit to larger projects. Why don't you DM some ideas you're thinking of?
I'd enjoy making some small with other people, but I don't want to work with strangers and none of my friends are artists or programmers any more. I have one musician friend but he's retired, and the only artists I know are ex-gfs and I'm not hitting them up for art. So I don't really have anyone to work with.
I should probably look and see if they've restarted doing live game jams because would be fun to go and work with a team for a day.
are you going to be making the whole engine or use a version of RPG Maker? those are surprisingly full-featured and don't have to feel like RPG Maker games, you can customize nearly everything and even use scripting to make entirely different genres in that engine
This thread has made me start looking into game dev for fun. It seems like it is super easy to actually get into with tools these days compared to a decade ago.
are you guys trying to be cagey about what you're working on like a real game company? :P
This thread has made me start looking into game dev for fun. It seems like it is super easy to actually get into with tools these days compared to a decade ago.
It's never been easier, there's never been more resources available for people who want to, and the tools have never been better or cheaper (there is pretty much an extremely high quality freeware version of anything you might choose to use)
game maker was so shitty back then :lol
at the time it was barely graduated from (IIRC) having been a teaching tool a teacher made to teach a class about game creation?
the only way to include background music was to have it in midi format, and whatever engine they were using to play it caused the entire game to freeze for a few frames whenever the music looped :doge
[SerializeField] GameObject pauseMenu;
public void Resume1()
{
pauseMenu.SetActive(false);
}
All I can say is: I hear you.
I started Blender tutorials and stepped away for a couple months. I'm as puzzled as a newborn child.
public class VolumeSlider : MonoBehaviour
{
public void Volume(float vol)
{
AudioListener.volume = vol;
}
}
But uhhhhh, I've completely forgotten everything I learned about coding in Unity having been away from it for two months :cry
If I take time off from coding, its not even a motivation thing, I legit forget actual coding and get back and look at stuff and go "what the fuck is a boolean? ???" :lol
Made the pause menu with placeholders and it worked. Added a volume slider and spent way too much time trying to figure out how to adjust the AudioListener since like everyone result on google was about changing individual audiosources or audiomixer but I just wanted an overall volume control.
what kind of game are you thinking?
an RPG where your main character is a low level mage who languished in his studies and just became an enchanted hot dog vendor, he conjures up hot dogs and sells them on the street corner, and everyone likes his hot dogs and he doesn't really have much ambition
but then his condiment supplier is interrupted due to a war and tariffs and sanctions so he is forced to buy black market condiments, which have been sabotaged by an agent on the other side of the war who knows the royalty have a penchant for hot dogs
so his latest batch of hot dogs transform people into actual dogs, and he gets blamed for it and is forced to flee the city, and this is the impetus for his adventure, to uncover who has framed him and restore his good name
and you attack by flinging enchanted hot dogs at your enemies which are augmented by various spell effects
:thinking
first person RPG like wizardry GB?
https://www.youtube.com/watch?v=1hlJr_3Dh9s
I started learning html for a work thing. I've never looked into it before.
I'm like what's a .css file? What's a </div>? etc...
Vertically align your div in another div
WITHOUT FLEX BOX CHEATING :bolo
Custom style your checkbox
without Javascript :bolo
Fix the Firefox font aliasing
No seriously, fix it.
-moz-osx-font-smoothing: grayscale;
@-moz-document url-prefix() {
body {
font-weight: lighter !important;
}
}