Processing - If statement and ids - processing

I'm an Italian student and I'm new in programming. I need your help for a school project.
I'm making a blob tracking program using Daniel Shiffman's tutorials. Currently I have 2 blobs on the screen. I am identifying them with 2 IDs: number 0 and number 1.
I need to put some conditions on those blobs: if one blob is in a certain part of the screen and the other one is in another part, I need to call a function.
I don't know how to put the if conditions separately for the two ids. Below is some pseudo code of what I would like to achieve:
for (id==0)
if (...) and
for (id==1)
if(...) then {
void()
}
I would really appreciate any help!

I don't really know where you want the blobs to be when the desired function fires, but I can try to give you an example...
Blob
Assign some sort of position variable, in this case PVector, to your blob object.
class Blob {
PVector position;
Blob (PVector position) {
this.position = position;
}
void update() {
*random movements, etc...*
}
}
Create two blob objects
Create two objects and assign a position to each of them.
Blob[] blobs = new Blob[2];
void setup() {
size(400, 400);
blobs[0] = new Blob(5, new PVector(40, 40));
blobs[1] = new Blob(13, new PVector(100, 100));
}
Check if blobs is at left or right side of the screen
I check if blob[0] is at the left side of the screen and if blob[1] is at right side of the screen. If they are, at the same time, the desiredFunction(); will fire.
void draw() {
for (int i = 0; i < blobs.length; i++) {
blobs.update();
}
if (blobs[0].position.x < (width / 2) && blobs[1].position.x < (width / 2) {
desiredFunction();
}
}
Remember
This is just an example. You could of course check other parts of the screen instead of the left and right parts. You can also use IDs on your blobs instead of an array, I just thought it was better to just use an array in this case.
PS: I wrote this answer without having processing started. The code has certainly a couple of typing errors.

For the example you have described, you can achieve this using the && operator in one if statement.
First assign the conditions you want to test to boolean variables. For example, create the boolean variables id0IsThere, and id1IsThere, and set them to true if the blobs are in the locations you want them to be in. Then use the following if statement:
if (id0IsThere && id1IsThere) {
yourFunction();
}
The && operator means that the code inside the if statement that executes yourFunction() is only executed if both conditions are true. In this case, if both blobs are in the positions you want them to be in. Hope that helps. Read more about if statements and the && operator here:
https://processing.org/reference/if.html
https://processing.org/reference/logicalAND.html

Related

AS3 Particle Explosion Crash

Hellooooo, hope y'all are doing great.
A while ago, I asked a question about how to do particle explosions in AS3 when I was coming from AS2. Luckily, I got help from Organis (thank you so much btw), but every time I try export the animation in SWF, it keeps crashing my file and I'm not sure why?
I should probably preface that what I'm doing is specifically for animation. I'm not trying to make a game, just a simple script where the movieclip I created can explode into different objects in its timeline...if that made any sense.
In case anyone needs the actual file itself, you can download it right here: https://sta.sh/018lqswjfmp2
Here is the AS2 version in case anyone needs it: https://sta.sh/02fzsqon3ohw
Here is the code given to me by Organis:
// Allows the script to interact with the Particle class.
import Particle;
// Number of particles.
var maxparticles:int = 200;
// I imagine you will need to access the particles somehow
// in order to manipulate them, you'd better put them into
// an Array to do so rather then address them by their names.
var Plist:Array = new Array;
// Counter, for "while" loop.
var i:int = 0;
// The loop.
while (i < maxparticles)
{
// Let's create a new particle.
// That's how it is done in AS3.
var P:Particle = new Particle;
// The unique name for the new particle. Whatever you want it for.
P.name = "particle" + i;
// Enlist the newly created particle.
Plist.push(P);
// At the moment, the P exists but is not yet attached to the display list
// (or to anything). It's a new concept, there wasn't such thing in AS2.
// Let's make it a part of the display list so that we can see it.
addChild(P);
i++;
}
And in case anyone needs it, here is the code I used for AS2:
maxparticles = 200; //number of particles
i = 0; //counter, for "while" loop
while(i < maxparticles){
newparticlename = "particle" + i; //creates a new name for a new particle instance
particle.duplicateMovieClip(newparticlename, i); //duplicates our particle mc
i++;
}

How can I randomize a video to play after another by pressing a key on Processing?

I'm quite new to Processing.
I'm trying to make Processing randomly play a video after I clear the screen by mouseclick, so I create an array that contain 3 videos and play one at a time.
Holding 'Spacebar' will play a video and release it will stop the video. Mouseclick will clear the screen to an image. The question is how can it randomize to another video if I press spacebar again after clear the screen.
I've been searching all over the internet but couldn't find any solution for my coding or if my logic is wrong, please help me.
Here's my code.
int value = 0;
PImage photo;
import processing.video.*;
int n = 3; //number of videos
float vidN = random(0, n+1);
int x = int (vidN);
Movie[] video = new Movie[3];
//int rand = 0;
int index = 0;
void setup() {
size(800, 500);
frameRate(30);
video = new Movie[3];
video[0] = new Movie (this, "01.mp4");
video[1] = new Movie (this, "02.mp4");
video[2] = new Movie (this, "03.mp4");
photo = loadImage("1.jpg");
}
void draw() {
}
void movieEvent(Movie video) {
video.read();
}
void keyPressed() {
if (key == ' ') {
image(video[x], 0, 0);
video[x].play();
}
}
void mouseClicked() {
if (value == 0) {
video[x].jump(0);
video[x].stop();
background(0);
image(photo, 0, 0);
}
}
You have this bit of logic in your code which picks a random integer:
float vidN = random(0, n+1);
int x = int (vidN);
In theory, if you want to randomise to another video when the spacebar is pressed again you can re-use this bit of logic:
void keyPressed() {
if (key == ' ') {
x = int(random(n+1));
image(video[x], 0, 0);
video[x].play();
}
}
(Above I've used shorthand of the two lines declaring vidN and x, but the logic is the same. If the logic is harder to follow since two operations on the same line (picking a random float between 0,n+1 and rounding down to an integer value), feel free to expand back to two lines: readability is more important).
As side notes, these bit of logic look a bit off:
the if (value == 0) condition will always be true since value never changes, making both value and the condition redundant. (Perhaps you plan to use for something else later ? If so, you could save separate sketches, but start with the simplest version and exclude anything you don't need, otherwise, in general, remove any bit of code you don't need. It will be easier to read, follow and change.)
Currently your logic says that whenever you click current video resets to the start and stops playing and when you hit the spacebar. Once you add the logic to randomise the video that the most recent frame of the current video (just randomised) will display (image(video[x], 0, 0);), then that video will play. Unless you click to stop the current video, previously started videos (via play()) will play in the background (e.g. if they have audio you'll hear them in the background even if you only see one static frame from the last time space was pressed).
Maybe this is the behaviour you want ? You've explained a localised section of what you want to achieve, but not overall what the whole of the program you posted should do. That would help others provide suggestions regarding logic.
In general, try to break the problem down to simple steps that you can test in isolation. Once you've found a solid solution for each part, you can add each part into a main sketch one at a time, testing each time you add something. (This way if something goes wrong it's easy to isolate/fix).
Kevin Workman's How To Program is a great article on this.
As a mental excercise it will help to read through the code line by line and imagine what it might do. Then run it and see if the code behaves as you predicted/intended. Slowly and surely this will get better and better. Have fun learning!

Unity 2D: NullReferenceException. How to add two manager scripts?

I am quite new to Unity, so please bear with my horrible explanation. I have followed a tutorial on youtube about a 2D fighting game: https://www.youtube.com/watch?v=n8S3WgVoOmo&t=3319s
I will provide my code below.
In the linked video, the video-maker makes one PlayerManager script which controls both my player and duplicates of my player. Through a simple AI, the duplicate becomes my enemy and we fight. This much works as expected.
Now I wanted to change it a bit like a 2D platformer. I took the PlayerManager and split it into two. AIManager (same code as in tutorial overall) and a PlayerManager with some changes. This also worked well and I am able to move and the AI also recognises me. The problem comes from a script called DamageScript. It recognizes if and when I take damage, and triggers the relevant animation.
When the DamageScript was connected to just the PlayerManager, when I hit the AI or AI hit me, whoever got hit showed the Damage animation. But after the split I did, with the separate Managers for AI and Player, I have two options. Either I hit the AI, he does Damage animation and when he hits me I get and error. Or he hits me, I have the Damage animations and when I hit him I get an error. The error is this:
NullReferenceException: Object reference not set to an instance of an object
DamageScript.OnTriggerEnter2D (UnityEngine.Collider2D col) (at Assets/Scripts/DamageScript.cs:19)
This is the original DamageScript:
public class DamageScript : MonoBehaviour {
void OnTriggerEnter2D(Collider2D col)
{
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger)
{
if (!col.transform.GetComponent<AIManager>().damage && !col.transform.GetComponent<PlayerManager>().blocking)
{
col.transform.GetComponent<AIManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
}
}
}
This way my Player does the Damage animation, I get the error when I hit. So, I figured something like this would work, but I guess I don't really know how to code it:
void OnTriggerEnter2D(Collider2D col)
{
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger)
{
line 11 if (!col.transform.GetComponent<AIManager>().damage && !col.transform.GetComponent<AIManager>().blocking)
{
col.transform.GetComponent<AIManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
else
{
if (!col.transform.GetComponent<PlayerManager>().damage)
{
line 19 col.transform.GetComponent<PlayerManager>().damage = true;
col.transform.root.GetComponentInChildren<Animator>().SetTrigger("Damage");
}
}
}
}
}
Not surprisingly, it doesn't work and I still get crashes on some hits.
Any help would be appreciated, if possible.
Thank you!
From the situation you've described, I'll assume the error is being, primarily, by faulty refactoring of responsibility delegation.
More specifically, I believe it's sufficiently clear that the tutorial you've followed didn't follow single responsibility principle properly, and instead, implemented multiple responsibilities (player and AI) on a single class/file, to save time for the video, or to simplify the tutorial.
Later, when splitting the responsibilities to two scripts and two objects, you, as a beginner, was/is unaware of some details and/or pitfalls involved in reference management, and so are failing to assign references to both objects, or failing to handle missing references as the scripts are now split.
The problem arises because, if your player and AI now have different sets of scripts; one with each manager, but neither with both (unlike before, when both player and AI objects had "both"); then, either on the first or second if*manager.damage statement, the manager in question would not be found with GetComponent because it's not in that object, and upon trying to access fields/properties/methods on a null reference, the NullReferenceException would be thrown.
The solution is simply to do the proper null checks before accessing such fields/properties/methods, to guard from the exception and proceed to the second if statement if the first's manager is found to be null.
While at it, might as well cache the queries to make things better, as RetiredNinja recommended in the comments.
Code:
void OnTriggerEnter2D(Collider2D col) {
if(col.transform.root != transform.root && col.tag != "Ground" && !col.isTrigger) {
//Cache to avoid multiple queries and to simplify access
var playermanager = col.transform.GetComponent<PlayerManager>(); //One of these won't be found and will receive null instead
var aiManager = col.transform.GetComponent<AIManager>(); //One of these won't be found and will receive null instead
var animator = col.transform.root.GetComponentInChildren<Animator>();
if (aiManager != null //Null-check was missing
&& !aiManager.damage && !aiManager.blocking) { //Much nicer
aiManager.damage = true;
if(animator!=null)
animator.SetTrigger("Damage");
}
else {
if (playerManager != null && !playerManager.damage) {
playerManager.damage = true;
animator.SetTrigger("Damage");
}
}
}
}

How do i get the text of a UI element to move in Unity 4.6+?

When the player approaches an item I want some of it's properties to be displayed, but I don't want that info to cover up the player. I have the following code which does not work.
t = GetComponentInChildren<Text> ();
void OnTriggerEnter(Collider col){
if (col.gameObject.tag.Equals ("Player")) {
playerInRange = true;
col.GetComponent<Controller>().itemsInRange.Add(this.gameObject);
GetComponentInChildren<Canvas> ().enabled = true;
}
if (player.transform.position.x < this.transform.position.x) {
Debug.Log ("On yer right!");
t.rectTransform.position.Set(this.transform.position.x+50, this.transform.position.z, this.transform.position.z);
}
if (player.transform.position.x > this.transform.position.x) {
t.rectTransform.position.Set(this.transform.position.x-50, this.transform.position.z, this.transform.position.z);
}
}
The Debug.Log shows up, so all conditions are being met, but the text is not moving. Anyone have any ideas?
The issue is that the getter for tranform.position returns a 'copy' of the position Vector3, so calling Set will only change the 'copy' of that vector3 and not the position of the rect transform.
This is because Vector3 is a struct and not a class and therefore isnt passed via reference. https://msdn.microsoft.com/en-us/library/ms173109.aspx
so instead of calling set i would assign a new vector 3 to the position variable
t.rectTransform.position = new Vector3(transform.position.x-50, transform.position.y, transform.position.z);
If you're hitting the debug, can you verify the position you are displaying is where you expect it to be, currently the second and third parameters to the 'Set' method is:
this.transform.position.z
Wouldn't the middle one be expected to be position.y?

Flixel Game Over Screen

I am new to game development but familiar with programming languages. I have started using Flixel and have a working Breakout game with score and lives.
I am just stuck on how I can create a new screen/game over screen if a player runs out of lives. I would like the process to be like following:
Check IF lives are equal to 0
Pause the game and display a new screen (probably transparent) that says 'Game Over'
When a user clicks or hits ENTER restart the level
Here is the function I currently have to update the lives:
private function loseLive(_ball:FlxObject, _bottomWall:FlxObject):void
{
// check for game over
if (lives_count == 0)
{
}
else
{
FlxG:lives_count -= 1;
lives.text = 'Lives: ' + lives_count.toString()
}
}
Here is my main game.as:
package
{
import org.flixel.*;
public class Game extends FlxGame
{
private const resolution:FlxPoint = new FlxPoint(640, 480);
private const zoom:uint = 2;
private const fps:uint = 60;
public function Game()
{
super(resolution.x / zoom, resolution.y / zoom, PlayState, zoom);
FlxG.flashFramerate = fps;
}
}
}
There are multiple ways to go about doing this...
You could use different FlxStates, like I described in the answer to your other post: Creating user UI using Flixel, although you'll have to get smart with passing the score or whatever around, or use a Registry-type setup
If you want it to actually work like you described above, with a transparent-overlay screen, you can try something like this (keep in mind, the exact details may differ for your project, I'm just trying to give you an idea):
First, make sure you have good logic for starting a level, lets say it's a function called StartLevel.
You'll want to define a flag - just a Boolean - that tracks whether or not the game is still going on or not: private var _isGameOver:Boolean; At the very end of StartLevel(), set this to false.
In your create() function for your PlayState, build a new FlxGroup which has all the things you want on your Game Over screen - some text, an image, and something that says "Press ENTER to Restart" (or whatever). Then set it to visible = false. The code for that might look something like:
grpGameOver = new FlxGroup();
grpGameOver.add(new FlxSprite(10,10).makeGraphic(FlxG.Width-20,FlxG.Height-20,0x66000000)); // just a semi-transparent black box to cover your game screen.
grpGameOver.add(new FlxText(...)); // whatever you want to add to the group...
grpGameOver.visible = false;
add(grpGameOver); // add the group to your State.
Depending on how your game is setup, you may also want to set the objects in your group's scrollFactor to 0 - if your game screen scrolls at all:
grpGameOver.setAll("scrollFactor", new FlxPoint(0,0));
In your update() function, you'll need to split it into 2 parts: one for when the game is over, and one for if the game is still going on:
if (_isGameOver)
{
if (FlxG.keys.justReleased("ENTER"))
{
grpGameOver.visible = false;
StartLevel();
}
}
else
{
... the rest of your game logic that you already have ...
}
super.update();
Keep in mind, if you have things that respond to user input anywhere else - like a player object or something, you might need to change their update() functions to check for that flag as well.
Then, the last thing you need to do is in your loseLive() logic:
if (lives_count == 0)
{
_isGameOver = true;
grpGameOver.visible = true;
}
else
...
That should do it!
I would highly recommend spending some time with different tutorials and sample projects to kind of get a better feel for Flixel in general. Photon Storm has some great material to play with (even though he's jumped over to HTML5 games)
I also want to note that if you get comfortable with the way Flixel handles updates, you can get really smart with your state's update() function and have it only call update on the grpGameOver objects, instead of having to change all your other objects updates individually. Pretty advanced stuff, but can be worth it to learn it.

Resources