So I need to detect the collision of multiple objects that are stored in two different arrays or arrayLists. I have confirmed that the collision detection method itself is functioning properly. The problem is that the objects colliding are supposed to disappear and be removed from the array, and I'm not sure how to go about this.
public class GamePanel extends PApplet{
private boolean myRunningStatus;
private final int HEIGHT = 700;
private final int WIDTH = 1200;
private final int SHOT_SPEED = -20;
private int numStars = 0, numEnemies = 0;
private Hero hero;
private Enemy[] enemies;
private List <Star> stars;
public GamePanel(){
myRunningStatus = true;
createEnemies();
createStars();
createHero();
updateEnemies();
}
public void createEnemies(){
enemies = new Enemy[10];
for (int i=0; i<enemies.length; i++){
enemies[i] = new Enemy(random(1, WIDTH), random(1, HEIGHT), 5, 20);
}
}
public void createHero(){
hero = new Hero(mouseX, mouseY);
}
public void createStars(){
stars = new ArrayList <Star>();
}
public Star generateStar(){
Star star = new Star(hero.getHeroX(), hero.getHeroY());
return star;
}
public void setup(){
background(255);
size(WIDTH, HEIGHT);
hero.render(this);
}
public void draw(){
if(myRunningStatus){
background(255);
hero.render(this);
for(int i=0; i<enemies.length; i++){
enemies[i].render(this);
enemies[i].move();
}
for(int i=0; i<stars.size(); i++){
if(stars.get(i) != null){
stars.get(i).render(this);
stars.get(i).move(SHOT_SPEED);
if(stars.get(i).getYPos() < 0){
stars.remove(i);
}
}
}
}
}
//this is the method I'm using to find the collisions between the objects and remove them
public void updateEnemies(){
for(int i=0; i<enemies.length; i++){
for(int j=0; j<stars.size(); j++){
if(enemies[i].starHit(stars.get(j))){
stars.set(j, null);
enemies[i] = null;
}
}
}
}
public void mouseMoved(){
if(myRunningStatus){
hero.setHeroX(mouseX);
hero.setHeroY(mouseY);
}
}
public void mouseClicked(){
for (int i=0; i<10;){
stars.add(i, generateStar());
break;
}
}
Instead of setting things equal to null, it would be better to remove them outright from the list. I would use an ArrayList for both enemies and stars, then call list.remove(i) during collision detection. Don't forget that this will change the size of the list, so you'll have to do i-- every time you remove an element to compensate.
Also, this confused me. You set elements of enemies equal to null:
if(enemies[i].starHit(stars.get(j))){
stars.set(j, null);
enemies[i] = null;
}
But don't check for it here, so shouldn't you be getting NPEs?
for(int i=0; i<enemies.length; i++){
enemies[i].render(this);
enemies[i].move();
}
Related
int[] moodIconRes = {
R.drawable.ic_emoticon_01, R.drawable.ic_emoticon_02, R.drawable.ic_emoticon_03,
R.drawable.ic_emoticon_04, R.drawable.ic_emoticon_05, R.drawable.ic_emoticon_06,
R.drawable.ic_emoticon_07, R.drawable.ic_emoticon_08, R.drawable.ic_emoticon_09,
R.drawable.ic_emoticon_10, R.drawable.ic_emoticon_11, R.drawable.ic_emoticon_12
};
Right now I am using it as a drawable.
private void setData1(HashMap<Integer, Integer> hashMap) {
ArrayList entries = new ArrayList<>();
int totalCount = 0; // 총 기분 수 (전체, 올해, 이번달마다 달라지는 값이므로 호출마다 초기화)
maxMoodIndex = -1; // 제일 많은 기분 종류
maxCount = -1; // 제일 많은 기분의 개수
colors.clear(); // 파이차트를 구성할 색깔배열 clear (전체, 올해, 이번달마다 달라지는 값이므로 clear 필요)
for(int i = 0; i < 12; i++) {
int count = 0;
if(hashMap.containsKey(i)) {
count = hashMap.get(i);
setMoodCount(i, count);
totalCount += count;
addColor(i); // 기분 종류에 맞게 색깔 설정
entries.add(new PieEntry(
count,
"",
ContextCompat.getDrawable(requireContext(), moodIconRes[i])
));
} else {
setMoodCount(i, count); // 개수 0
}
}
I wonder if there is a way to call it in the form of a bitmap or r.id.imageview rather than a drawable image in this part. I'd appreciate it if someone could give me an idea.
You can use BitmapDrawable
Drawable d = new BitmapDrawable(getResources(), bitmap);
I was able to follow the csharp-sample-apps from the github repo for Affectiva. I ran the demo using my webcam and the processing and performance was great.I am not getting the same processing speed from the PhotoDetector when I try to run it over images in filesystem. Any help or improvement would be appreciated.
namespace Logical.EmocaoFace
{
public class AnaliseEmocao : Affdex.ImageListener, Affdex.ProcessStatusListener
{
private Bitmap img { get; set; }
private Dictionary<int, Affdex.Face> faces { get; set; }
private Affdex.Detector detector { get; set; }
private ReaderWriterLock rwLock { get; set; }
public void processaEmocaoImagem()
{
for (int i = 0; i < resultado.count; i++){
RetornaEmocaoFace();
if (faceAffdex != null)
{
}
}
}
public void RetornaEmocaoFace(string caminhoImagem)
{
Affdex.Detector detector = new Affdex.PhotoDetector(1, Affdex.FaceDetectorMode.LARGE_FACES);
detector.setImageListener(this);
detector.setProcessStatusListener(this);
if (detector != null)
{
//ProcessVideo videoForm = new ProcessVideo(detector);
detector.setClassifierPath(#"D:\Desenvolvimento\Componentes\Afectiva\data");
detector.setDetectAllEmotions(true);
detector.setDetectAllExpressions(false);
detector.setDetectAllEmojis(false);
detector.setDetectAllAppearances(false);
detector.start();
((Affdex.PhotoDetector)detector).process(LoadFrameFromFile(caminhoImagem));
detector.stop();
}
}
static Affdex.Frame LoadFrameFromFile(string fileName)
{
Bitmap bitmap = new Bitmap(fileName);
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int numBytes = bitmap.Width * bitmap.Height * 3;
byte[] rgbValues = new byte[numBytes];
int data_x = 0;
int ptr_x = 0;
int row_bytes = bitmap.Width * 3;
// The bitmap requires bitmap data to be byte aligned.
// http://stackoverflow.com/questions/20743134/converting-opencv-image-to-gdi-bitmap-doesnt-work-depends-on-image-size
for (int y = 0; y < bitmap.Height; y++)
{
Marshal.Copy(ptr + ptr_x, rgbValues, data_x, row_bytes);//(pixels, data_x, ptr + ptr_x, row_bytes);
data_x += row_bytes;
ptr_x += bmpData.Stride;
}
bitmap.UnlockBits(bmpData);
//Affdex.Frame retorno = new Affdex.Frame(bitmap.Width, bitmap.Height, rgbValues, Affdex.Frame.COLOR_FORMAT.BGR);
//bitmap.Dispose();
//return retorno;
return new Affdex.Frame(bitmap.Width, bitmap.Height, rgbValues, Affdex.Frame.COLOR_FORMAT.BGR);
}
public void onImageCapture(Affdex.Frame frame)
{
frame.Dispose();
}
public void onImageResults(Dictionary<int, Affdex.Face> faces, Affdex.Frame frame)
{
byte[] pixels = frame.getBGRByteArray();
this.img = new Bitmap(frame.getWidth(), frame.getHeight(), PixelFormat.Format24bppRgb);
var bounds = new Rectangle(0, 0, frame.getWidth(), frame.getHeight());
BitmapData bmpData = img.LockBits(bounds, ImageLockMode.WriteOnly, img.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int data_x = 0;
int ptr_x = 0;
int row_bytes = frame.getWidth() * 3;
// The bitmap requires bitmap data to be byte aligned.
// http://stackoverflow.com/questions/20743134/converting-opencv-image-to-gdi-bitmap-doesnt-work-depends-on-image-size
for (int y = 0; y < frame.getHeight(); y++)
{
Marshal.Copy(pixels, data_x, ptr + ptr_x, row_bytes);
data_x += row_bytes;
ptr_x += bmpData.Stride;
}
img.UnlockBits(bmpData);
this.faces = faces;
frame.Dispose();
}
public void onProcessingException(Affdex.AffdexException A_0)
{
throw new NotImplementedException("Encountered an exception while processing " + A_0.ToString());
}
public void onProcessingFinished()
{
string idArquivo = CodEspaco + "," + System.Guid.NewGuid().ToString();
for(int i = 0; i < faces.Count; i++)
{
}
}
}
public static class GraphicsExtensions
{
public static void DrawCircle(this Graphics g, Pen pen,
float centerX, float centerY, float radius)
{
g.DrawEllipse(pen, centerX - radius, centerY - radius,
radius + radius, radius + radius);
}
}
}
Found the answer to my own question:
Using PhotoDetector is not ideal in this case since it is expensive to use the Face Detector configuration on subsequent frame calls.
The best option to improve the performance would be to use an instance of the FrameDetector Class.
Here is a getting started guide to analyze-frames.
I modified a little bit the Real Time Line Chart example to show two LineChart like the code below.
Problem: the ViewPort is moving incorrectly does not work properly. It is moving much faster than real points (Entry) are added. In other words, the Entry get added in the wrong place and the ViewPort keeps moving right uncontrollably. It should move right only gradually as each Entry is added. Please help me to fix this one.
private int year = 2015;
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
private int[] mColors = {Color.BLUE,Color.YELLOW,Color.CYAN,Color.MAGENTA,Color.GREEN};
private int mCurrentColorIndex = 0;
private synchronized void addEntry(String id, float value) {
LineData data = mChart.getData();
if (data != null) {
ILineDataSet set = data.getDataSetByLabel(id,true);
//ILineDataSet set1 = data.getDataSetByIndex(0);
if (set == null) {
set = createSet(id, mColors[(mCurrentColorIndex++)%mColors.length ]);
data.addDataSet(set);
}
String xValue = sdf.format(new Date());
// add a new x-value first
data.addXValue(xValue);
set.addEntry(new Entry(value, set.getEntryCount(), 0));
// let the chart know it's data has changed
mChart.notifyDataSetChanged();
// limit the number of visible entries
mChart.setVisibleXRangeMaximum(30);
// mChart.setVisibleYRange(30, AxisDependency.LEFT);
// move to the latest entry
mChart.moveViewToX(data.getXValCount() - 31);
// this automatically refreshes the chart (calls invalidate())
// mChart.moveViewTo(data.getXValCount()-7, 55f,
// AxisDependency.LEFT);
}
}
private LineDataSet createSet(String label, int color) {
LineDataSet set = new LineDataSet(null, label);
set.setAxisDependency(AxisDependency.LEFT);
set.setColor(color);
set.setCircleColor(Color.WHITE);
set.setLineWidth(2f);
set.setCircleRadius(4f);
set.setFillAlpha(65);
set.setFillColor(color);
set.setHighLightColor(Color.rgb(244, 117, 117));
set.setValueTextColor(Color.WHITE);
set.setValueTextSize(9f);
set.setDrawValues(false);
return set;
}
private void feedMultiple() {
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 50; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry("name1", (float)(Math.random() * 40) + 30f);
}
});
try {
Thread.sleep(35);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 100; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry("name2", (float)(Math.random() * 40) + 30f);
}
});
try {
Thread.sleep(35);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Resolved in the comments by #Tony with the following change:
//set.addEntry(new Entry(value, set.getEntryCount(), 0)); //incorrect
set.addEntry(new Entry(value, data.getXValCount(), 0)); //correct
Explanation:
A LineData is composed of multiple ILineDataSet:
set.getEntryCount() returns the number of y-values in one DataSet and is effectively equivalent to yvals.size().
data.getXValCount() returns the total number of x-values the ChartData object represents.
Since we wish to add an entry at the last x-index, we should use data.getXValCount()
NOTE:
In MPAndroidCharts 3.0.1 data.getXValCount() is no longer present. You can instead use data.getXMax() + 1 instead.
I'm trying to create a basic function that calls on a method that creates the 2D ArrayList that will be used further in the main program to do things like calculate the row and column sums as well as print out the triangle.
However, after it runs the ArrayList returns null. What's going on?
Thanks,
public class Trib
{
private ArrayList<ArrayList<Integer>> triangle;
private int Asize;
public Trib (int size)
{
// convert the argument to type 'int' to be used in the program
Asize = size;
// create an ArrayList of ArrayLists, it will have 'size' number ArrayLists contained within
ArrayList<ArrayList<Integer>> triangle = new ArrayList<ArrayList<Integer>>(size);
// create the inner ArrayLists
for (int i = 0; i < size; i++)
{
// add to index 'i' of our ArrayList a new ArrayList of size (i+1)
triangle.add(new ArrayList<Integer>(i+1));
for (int j = 0; j <= i; j++)
{
if (j==0 || j == i)
{
triangle.get(i).add(1);
}
else
triangle.get(i).add(triangle.get(i-1).get(j-1)+triangle.get(i-1).get(j));
System.out.print(triangle.get(i).get(j) + " ");
}
System.out.println();
}
triangle.clone();
}
public void printTriangle()
{
System.out.print(triangle.get(1).get(1));
/*for (int i = 0; i < Asize; i++)
{
for (int j = 0; j <= i; j++)
{
System.out.print(triangle.get(1).get(1) + " ");
}
System.out.println();
}*/
}
/*public Trib()
{
this(5);
}*/
/*public int Psize()
{
return triangle.size();
}
public ArrayList<Integer> sumRows()
{
ArrayList<Integer> row_sum = new ArrayList<Integer>(Asize);
for (int i = 0; i < Asize; i++)
{
for (int j = 0; j < i; j++)
{
row_sum.add(triangle.get(i).get(j));
}
}
return row_sum;
}
public ArrayList<Integer> sumCols()
{
ArrayList<Integer> col_sum = new ArrayList<Integer>(Asize);
for (int i = 0; i < Asize; i++)
{
for (int j = 0; j < i; j++)
{
col_sum.add(triangle.get(i).get(i));
}
}
return col_sum;
}*/
public static void main(String[] args)
{
if(args.length < 1)
{
System.err.println("Sorry, this program needs an integer argument.");
System.exit(1);
}
Trib pt = new Trib(Integer.parseInt(args[0]));
pt.printTriangle();
//ArrayList<Object> sum_rows = new ArrayList<Object>(pt.Psize());
// sum_rows.add;
System.out.println("\nHere are the sum of rows:");
//for (int i = 0; i < pt.Psize(); i++)
//System.out.println(sum_rows.get(i));
//ArrayList<Integer> sum_cols = new ArrayList<Integer>(pt.Psize());
System.out.println("\nHere are the sum of columns:");
//for (int i = 0; i < pt.Psize(); i++)
//System.out.printf("%-5d", sum_cols.get(i));
}
}
Watch out what's what you are doing: Notice that you have TWO variables named "triangle": The first one is an instance variable and the second is a local variable, which is the only one you have initialized.
My suggestion to avoid this common mistake is to pre-pend "this." to any use of what you intend must be an instance variable. And, if in doubt, if you use a development environment as Eclipse, press CTRL and click on your variable to navigate to the point where it is declared.
I have a list like shown below. Assume it has 16 Container objects in it. Each Container object is a simple bean, with fields like age, weight, height, etc. How can I create a sub-list that contains common 'Container' objects if a 'Container' object is considered equal if the weight and height are equal?
List<Container> containers = new ArrayList<Container>();
If by "common" containers you mean duplicating ones, then this code might help you:
import java.util.ArrayList;
import java.util.List;
public class CommonContainers {
public static void main(String[] args) {
List<Container> containers = new ArrayList<Container>(16);
for(int i=0; i<13; i++) {
containers.add(new Container(i, i));
}
//add a few duplicating ones
containers.add(new Container(1,1));
containers.add(new Container(5,5));
containers.add(new Container(6,6));
List<Container> sublist = new ArrayList<Container>();
for (Container c1 : containers) {
for (Container c2 : containers) {
if(c1 != c2 && c1.equals(c2)) {
sublist.add(c1);
}
}
}
for (Container c : sublist) {
System.out.println(c);
}
}
private static class Container {
private int weight;
private int height;
#Override
public String toString() {
return String.format("Container[w=%d,h=%d]", weight, height);
}
public Container(int weight, int height) {
this.weight = weight;
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + height;
result = prime * result + weight;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Container other = (Container) obj;
if (height != other.height)
return false;
if (weight != other.weight)
return false;
return true;
}
}
}
If you mean something else or need clarification, please let me know.
Thanks John Smith for giving direction on this question. I used the iterator instead and was able to make a nice solution to what I was looking for. below is the solution. Note that .equals is overriden for the Containers comparison. The technique I used will take the master list and create a sub-list while removing elements from the parent list at the same time. The solution can be called recursivly until you convert the master list into a subset of lists.
public List<Container> extractCommonSubList(
List<Container> masterContainerList) {
List<Container> subList = new ArrayList<Container>();
ListIterator<Container> iterator = masterContainerList.listIterator();
// get first item from master list and remove from master list
Container firstContainer = iterator.next();
iterator.remove();
// Add first container to sublist
subList.add(firstContainer);
while (iterator.hasNext()) {
Container container = iterator.next();
// Search for matches
if (firstContainer.equals(container)) {
// containers are a match, continue searching for matches
subList.add(container);
iterator.remove();
continue;
} else {
break;
}
}
// return common list
return subList;
}