How do I properly Object Pool enemy waves with an IEnumerator - destroy

Hopefully someone can help me with this issue. I'm trying to couple an IEnumerator with my object pooling script to instantiate enemies in waves. But I can't get them to instantiate without immediately destroying themselves 2 or 3 times and then instantiating one wave of enemies and never spawning again. Can anyone help me see where I'm going wrong here?
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SpawnMaster : MonoBehaviour {
public int enemyCount = 4;
public float spawnWait=0.5f;
public float startWait=1;
public float waveWait=3;
public Transform[] spawnPoints;
private int currentWave = 0;
private int waveCount = 10;
private IEnumerator spawnWaves;
private IEnumerator goHorde;
bool isSpawning = false;
void Update()
{
if(!isSpawning)
{
isSpawning = true;
StartCoroutine(SpawnWaves(currentWave));
}
}
IEnumerator SpawnWaves (int currentWave)
{
Debug.Log("Spawning " + currentWave + "currentWave");
for (int i = 0; i < waveCount; i++)
{
StartCoroutine(GoHorde());
}
currentWave += 1;
yield return new WaitForSeconds (waveWait);
//We've spawned, so start another spawn
isSpawning = false;
}
IEnumerator GoHorde()
{
GameObject beetle01 = BeetlePool.current.GetPooledObject();
if(beetle01 == null)
yield return null;
// Only pick a new spawn point once per wave
int spawnPointIndex = Random.Range (0, spawnPoints.Length);
for (int j = 0; j < enemyCount; j++)
{
beetle01.transform.position = spawnPoints[spawnPointIndex].position;
beetle01.transform.rotation = spawnPoints[spawnPointIndex].rotation;
beetle01.SetActive(true);
yield return new WaitForSeconds (spawnWait);
}
}
}

I would change:
if(!isSpawning)
to:
if(isSpawning != true)
Or:
if(isSpawning == false)
Also if you are going to have multiple waves of enemies that are being instantiated and destroyed. You should look into object pooling to save memory.

Related

Memory leak in c++/CLI code

The test app:
static void Main(string[] args)
{
String connectionString = "DSN=DotNetUltraLightDSII; UID=user; PWD=pass";
String query = "select * from person";
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
connection.Open();
for (Int32 trial = 1; trial <= 100000; trial++)
{
if (0 == trial % 1000)
{
Console.WriteLine("Executing trial #{0:#,0}", trial);
GC.Collect();
}
using (OdbcCommand command = new OdbcCommand(query, connection))
{
using (OdbcDataReader reader = command.ExecuteReader())
{
do
{
while (reader.Read())
{
for (Int32 colIndex = 0; colIndex < reader.FieldCount; colIndex++)
{
Object x = reader[colIndex];
IDisposable d = x as IDisposable;
if (null != d)
{
d.Dispose();
}
d = null;
x = null;
}
}
} while (reader.NextResult());
reader.Close();
}
}
}
connection.Close();
}
Memory usage
Heap Snapshot Comparison
The memory usage just goes up over time. It seems like there are strong handles to the ULPersonTable but I cannot tell what exactly these strong handles are or where they are coming from. We are storing the instances of that type inside gcroot, but they seem to be destroyed. If someone could shed some light on this issue, that would be appreciated.
Regards
Ended up finding the problem. It was a pointer which wasn't being deleted properly.

Unity Iterate over a list to sort by the number value

I have a text file called highscore.txt and I know the format of the data going into the file which works in the following way:
Username:score
I then need to search through the whole file to see where the new score needs to be added such that the file is in order of score from largest to smallest
List<string> tempoaryList = new List<string>();
List<int> valueList = new List<int>();
string lineValues = "";
using (StreamReader sr = new StreamReader(finalPath))
{
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
tempoaryList.Add(lineValues);
int data = Convert.ToInt32(lineValues.Substring(lineValues.LastIndexOf(':') + 1));
valueList.Add(data);
}
}
valueList.Sort();
for(int i =0; i > valueList.Count; i++)
{
if(valueList[i] <= playerScore)
{
tempoaryList.Insert(i - 1, playerScore.ToString());
}
}
using (StreamWriter sw = new StreamWriter(finalPath, false))
{
for (int i = 0; i < tempoaryList.Count; i++)
{
sw.WriteLine(tempoaryList[i]);
Debug.Log(tempoaryList[i]);
}
}
The above just simply doesn't change the text file and leaves it as it was found, any ideas of what I am doing wrong?
You should change your code to this:
ScoreList.cs
using UnityEngine;
using System;
using System.IO;
using System.Collections.Generic;
public class ScoreList : MonoBehaviour {
private void Start() {
GameOver.GameOverEvent += UpdateScoreBoardFile;
}
private void UpdateScoreBoardFile(string playerName, int playerScore) {
string lineValues;
string finalPath = "[ScoreBoard File Location]";
List<string> tempoaryList = new List<string>();
List<int> valueList = new List<int>();
bool isScoreLowest = true;
using (StreamReader sr = new StreamReader(finalPath)) {
while (sr.EndOfStream == false) {
lineValues = sr.ReadLine();
tempoaryList.Add(lineValues);
int data = Convert.ToInt32(lineValues.Substring(lineValues.LastIndexOf(':') + 1));
valueList.Add(data);
}
}
if (tempoaryList != null) {
for (int i = 0; i < valueList.Count; i++) {
if (valueList[i] <= playerScore) {
tempoaryList.Insert(i, playerName + ":" + playerScore.ToString());
isScoreLowest = false;
break;
}
}
}
if (isScoreLowest) {
tempoaryList.Add(playerName + ":" + playerScore.ToString());
}
using (StreamWriter sw = new StreamWriter(finalPath, false)) {
for (int i = 0; i < tempoaryList.Count; i++) {
sw.WriteLine(tempoaryList[i]);
Debug.Log(tempoaryList[i]);
}
}
}
}
GameOver.cs (or wherever you manage the game over condition):
using UnityEngine;
using System;
public class GameOver : MonoBehaviour {
public static event Action<string, int> GameOverEvent;
string playerName;
int finalScore;
private void GameOver() {
//Do other stuff when the game is over
GameOverEvent(playerName, finalScore);
}
}
Explanation of the changes:
isScoreLowest is needed to Add the new lowest score at the end of the list, since the for loop won't add it by itself.
The if (tempoaryList != null) check is done to skip the for loop when the scoreboard is empty.
And you saved yourself from doing a Sort, which is always a good thing. :)

How to bind ComboBox to a list in JavaFX?

My application periodically adds Strings to a List using a Thread. I want to add those strings to a ComboBox as soon as they get added to the List. Is there anyway to bind a ComboBox to a List?
My Code:
static final int max = 20;
List<String> ips = new ArrayList<String>();
public void getIP() throws UnknownHostException {
Task task = new Task<Void>() {
#Override
public Void call() throws UnknownHostException {
InetAddress localhost = InetAddress.getLocalHost();
byte[] ip = localhost.getAddress();
for (int i = 10; i <= max; i++) {
if (isCancelled()) {
break;
}
try {
ip[3] = (byte) i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(100)) {
//============================== Populating List ===============//
ips.add(address.getHostName());
}
} catch (Exception e) {
System.err.println(e);
}
updateProgress(i, max);
}
return null;
}
};
//============================== Bind ComboBox to List Code here ===============//
indicator.progressProperty().bind(task.progressProperty());
new Thread(task).start();
}
No there is no way to bind a simple list, since it's not observable. Even with a ObservableList, there would be the problem of the updates coming from a different thread.
You could however use a synchronized list and use the value property to pass the current size, which would allow you to add the items via listener.
Example
This uses a ListView instead of a ComboBox, since the results are visible without user interaction, but you could also use targetList = comboBox.getItems().
#Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
List<String> targetList = listView.getItems();
final List<String> ips = Collections.synchronizedList(new ArrayList<>());
Task<Integer> task = new Task<Integer>() {
#Override
protected Integer call() throws Exception {
Random random = new Random();
int size;
for (size = 0; size < 100; size++) {
ips.add(Integer.toString(size));
updateValue(size);
Thread.sleep(random.nextInt(500));
}
return size;
}
};
task.valueProperty().addListener((observable, oldValue, newValue) -> {
// add values not yet in the target list.
for (int i = targetList.size(), newSize = newValue; i < newSize; i++) {
targetList.add(ips.get(i));
}
});
new Thread(task).start();
Scene scene = new Scene(listView);
primaryStage.setScene(scene);
primaryStage.show();
}
It would be a bit simpler though to simply post the updates on the ui thread using Platform.runLater though:
ips = comboBox.getItems();
Task task = new Task<Void>() {
#Override
public Void call() throws UnknownHostException {
InetAddress localhost = InetAddress.getLocalHost();
byte[] ip = localhost.getAddress();
for (int i = 10; i <= max; i++) {
if (isCancelled()) {
break;
}
try {
ip[3] = (byte) i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(100)) {
//============================== Populating List ===============//
final String hostName = address.getHostName();
// do update on application thread
Platform.runLater(() -> ips.add(hostName));
}
} catch (Exception e) {
System.err.println(e);
}
updateProgress(i, max);
}
return null;
}
};
i suggest you to do the following:
change
List<String> ips = new ArrayList<String>();
to
final ObservableList<String> ips = FXCollections.observableArrayList();
change:
Task task = new Task<Void>()
to
Task<ObservableList<String> task = new Task<>(){
#Override
public ObservableList<String> call() throws UnknownHostException {
...
return ips;
}
};
comboBox.itemsProperty().bind(task.valueProperty());

How do I pass a pointer to an array of pointers as an argument to a function?

I'm trying to code a robot, and I'm having a confusing situation. I need to pass an array of pointers to objects to a constructor of a class. I can't, however, populate the array before I pass it into the constructor. To solve this I want to pass a pointer to said array, and access its elements from the pointer. The problem is that I'm new to C++, and so I'm not sure of the syntax. Could you guys help me out?
Code for the main file
class RobotDemo : public SimpleRobot
{
Joystick stick;
JoystickOne joyOne;
Victor *victors [8];
public:
RobotDemo(void):
stick(1),
joyOne(&stick)// these must be initialized in the same order
// as they are declared above.
/*It doesnt seem like I can do anything but initialize things here*/
{
/*Populate array with pointers to victors. Will need to update channels*/
for (int x = 1; x <= 7; x++) {
victors[x] = new Victor(x);
}
/*And I don't think I can initialize anything here*/
myRobot.SetExpiration(0.1);
}
/**
* Drive left & right motors for 2 seconds then stop
*/
void Autonomous(void)
{
}
/**
* Runs the motors with arcade steering.
*/
void OperatorControl(void)
{
myRobot.SetSafetyEnabled(true);
while (IsOperatorControl())
{
joyOne.testForActions(); /*Check joystick one for actions*/
Wait(0.005); // wait for a motor update time
}
}
/**
* Runs during test mode
*/
void Test() {
}
};
START_ROBOT_CLASS(RobotDemo);
Here's the code for the JoystickInput class, which the JoystickOne class extends
//the .h
#ifndef JOYSTICKINPUT_H
#define JOYSTICKINPUT_H
#include "WPILib.h"
class JoystickInput {
public:
JoystickInput(Joystick*);
JoystickInput(Joystick*, Victor* [8]);
Joystick * joystick;
bool buttons [10];
Victor** victors [8];
bool buttonClicked(int id);
virtual void testForActions();
};
#endif
//and the .cpp
#include "JoystickInput.h"
JoystickInput::JoystickInput(Joystick * joy) {
joystick = joy;
for (int x = 0; x < 10; x++) {
buttons[x] = false;
}
}
JoystickInput::JoystickInput(Joystick * joy, Victor* vicArray [8]) {
joystick = joy;
for (int x = 0; x < 10; x++) {
buttons[x] = false;
}
for (int n = 0; n <=7; n++) {
*victors[n] = vicArray[n];
}
}
bool JoystickInput::buttonClicked(int id) {
if (buttons[id] == false and joystick->GetRawButton(id) == true) {
buttons[id] = true;
return true;
} else if (buttons[id] == true and joystick->GetRawButton(id) == false) {
buttons[id] = false;
return false;
} else {
return false;
}
}
void JoystickInput::testForActions() {
}
What I'm asking you guys to help me do is rework the constructor of JoystickInput() so that it also takes a pointer to an array of pointers (to Victors), and performs methods on elements of the array. Googling it hasnt turned up anything useful. I'd research it more myself, but its been a few days and I'm still hung up on this.
Thanks for the help (and if not that, then at least reading my post)!
You should be able to use:
JoystickInput(Joystick*, Victor**, int);
and just pass vicArray into the constructor. If victors can be anything else than an array of length 8, then you should also pass the length as an argument because c++ cannot find the length of an array from a pointer.
Whenever types get complicated (functions or arrays), use a typedef:
typedef char char_buffer_type[8]; //char_buffer_type is an array
typedef char (*char_buffer_ptr)[8]; //char_buffer_ptr is a pointer to an array
typedef char (&char_buffer_ref)[8]; //char_buffer_ref is a reference to an array
typedef int main_type(int, char**); //main_type is a "int(int, char**)" function
typedef Victor*(array_of_ptr)[8]; //array_of_ptr is an array of 8 Victor*
Also, you should name the values 8 and 10.
class JoystickInput {
public:
static const int victor_count = 8;
static const int button_count = 10;
typedef Victor*(array_of_victor_ptr)[victor_count];
JoystickInput(Joystick*){}
JoystickInput(Joystick*, array_of_victor_ptr& vicArray);
bool buttonClicked(int id){return true;}
virtual void testForActions(){}
Joystick * joystick;
bool buttons [button_count];
array_of_victor_ptr victors; //that's simpler
};
//then pass this one by reference
JoystickInput::JoystickInput(Joystick * joy, array_of_victor_ptr& vicArray) {
joystick = joy;
for (int x = 0; x < button_count; x++) {
buttons[x] = false;
}
for (int n = 0; n < victor_count; n++) {
victors[n] = vicArray[n]; //don't have to dereference here anymore
}
}
Proof of compilation. Typedefs are wonderful. Use them.

How do I made shooting multiple bullets function correctly using a for loop?

I'm working on a prototype for a shmup game in C++ using SDL...Right now I'm just trying to get the basics working without using classes. Now, I have it so it shoots multiple bullets, but it behaves strangely which I believe is because of the way the counter is reset...The bullets will appear and disappear, and some will keep blinking in the original spot they were shot at, and there will sometimes be a delay before any can be shot again even if the limit isn't on the screen...And sometimes the player character will suddenly jump way to the right and only be able to move up and down. How do I fix this so it smoothly shoots? I've included all relevent code...
[edit] Please note that I intend on cleaning it up and moving it all to a class once I get this figured out...This is just a simple prototype so I can have the basics of the game programmed in.
[edit2] ePos is the enemy position, and pPos is the player position.
//global
SDL_Surface *bullet[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
bool shot[10];
int shotCount = 0;
SDL_Rect bPos[10];
//event handler
case SDLK_z: printf("SHOT!"); shot[shotCount] = true; ++shotCount; break;
//main function
for(int i = 0; i <= 9; i++)
{
shot[i] = false;
bullet[i] = IMG_Load("bullet.png");
}
//game loop
for(int i = 0; i <= shotCount; i++)
{
if(shot[i] == false)
{
bPos[i].x = pPos.x;
bPos[i].y = pPos.y;
}
if(shot[i] == true)
{
bPos[i].y -= 8;
SDL_BlitSurface(bullet[i], NULL, screen, &bPos[i]);
if( (bPos[i].y + 16 == ePos.y + 16) || (bPos[i].x + 16 == ePos.x + 16) )
{
shot[i] = false;
}
else if(bPos[i].y == 0)
{
shot[i] = false;
}
}
}
if(shotCount >= 9) { shotCount = 0; }
Here is something like I was suggesting in the comment. It was just written off the top of my head but it gives you a general idea of what I'm talking about..
class GameObject
{
public:
int x;
int y;
int width;
int height;
int direction;
int speed;
GameObject()
{
x = 0;
y = 0;
width = 0;
height = 0;
direction = 0;
speed = 0;
}
void update()
{
// Change the location of the object.
}
bool collidesWidth(GameObject *o)
{
// Test if the bullet collides with Enemy.
// If it does, make it invisible and return true
}
}
GameObject bullet[10];
GameObject enemy[5];
while(true)
{
for(int x=0; x<=10;x++)
{
bullet[x].update();
for(int y=0;y<=5;y++)
{
if(bullet[x].collidesWith(&enemy[y])
{
// Make explosion, etc, etc.
}
}
}
}