I have a chat list view in the bubble notifications (https://developer.android.com/guide/topics/ui/bubbles) which has a swipe listener requiring the position of the listview items.
In a regular activity i get this through:
int[] mylistCoords = new int[2];
mListView.getLocationOnScreen(mylistCoords);
and then subtract the offset of the listview from the touchpoint to match the hitbox of the elements.
int x = (int) motionEvent.getRawX() - listViewCoords[0];
int y = (int) motionEvent.getRawY() - listViewCoords[1];
View child;
for (int i = 0; i < childCount; i++) {
child = mListView.getChildAt(i);
child.getHitRect(rect);
if (rect.contains(x, y)) {
mDownView = child;
break;
}
}
Now in the bubble this does not work anymore because getLocationOnScreen does not compute the offset of the ConversationBubbleView to the actual main screen. Instead it only considers the ConversationBubbleView as the full screen and as a result the the touch point is offset by the same amount toward the bottom.
Any ideas how I can get access to these coordinates? I tried all sorts
of DisplayMetrics/Display shenanigans to compute the offset manually with values from view.getY() ect. but it seems the Bubble Conversation is a encapsulated thing on its own and I cannot access stuff around it. Thanks in advance.
Related
I am trying to store the motion detected from optical flow for frames in a video sequence and then use these stored motion vectors in order to predict the already known frames using just the first frame as a reference. I am currently using two processing sketches - the first sketch draws a motion vector for every pixel grid (each of width and height 10 pixels). This is done for every frame in the video sequence. The vector is only drawn in a grid if there is sufficient motion detected. The second sketch aims to reconstruct the video frames crudely from just the initial frame of the video sequence combined with information about the motion vectors got from the first sketch.
My approach so far is as follows: I am able to determine the size, position and direction of each motion vector drawn in the first sketch from four variables. By creating four arrays (two for the motion vector's x and y coordinate and another two for its length in the x and y direction), every time a motion vector is drawn I can append each of the four variables to the arrays mentioned above. This is done for each pixel grid throughout an entire frame where the vector is drawn and for each frame in the sequence - via for loops. Once the arrays are full, I can then save them to a text file as a list of strings. I then load these strings from the text file into the second sketch, along with the first frame of the video sequence. I load the strings into variables within a while loop in the draw function and convert them back into floats. I increment a variable by one each time the draw function is called - this moves on to the next frame (I used a specific number as a separator in my text-files which appears at the end of every frame - the loop searches for this number and then increments the variable by one, thus breaking the while loop and the draw function is called again for the subsequent frame). For each frame, I can draw 10 by 10 pixel boxes and move then by the parameters got from the text files in the first sketch. My problem is simply this: How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Apologies for the length and complexity of my question. Any tips would be very much appreciated! I will add the code for the second sketch. I can also add the first sketch if required, but it's rather long and a lot of it is not my own. Here is the second sketch:
import processing.video.*;
Movie video;
PImage [] naturalMovie = new PImage [0];
String xlengths [];
String ylengths [];
String xpositions [];
String ypositions [];
int a = 0;
int c = 0;
int d = 0;
int p;
int gs = 10;
void setup(){
size(640, 480, JAVA2D);
xlengths = loadStrings("xlengths.txt");
ylengths = loadStrings("ylengths.txt");
xpositions = loadStrings("xpositions.txt");
ypositions = loadStrings("ypositions.txt");
video = new Movie(this, "sample1.mov");
video.play();
rectMode(CENTER);
}
void movieEvent(Movie m) {
m.read();
PImage f = createImage(m.width, m.height, ARGB);
f.set(0, 0, m);
f.resize(width, height);
naturalMovie = (PImage []) append(naturalMovie, f);
println("naturalMovie length: " + naturalMovie.length);
p = naturalMovie.length - 1;
}
void draw() {
if(naturalMovie.length >= p && p > 0){
if (c == 0){
image(naturalMovie[0], 0, 0);
}
d = c;
while (c == d && c < xlengths.length){
float u, v, x0, y0;
u = float(xlengths[a]);
v = float(ylengths[a]);
x0 = float(xpositions[a]);
y0 = float(ypositions[a]);
if (u != 1.0E-19){
//stroke(255,255,255);
//line(x0,y0,x0+u,y0+v);
PImage box;
box = get(int(x0-gs/2), int(y0 - gs/2), gs, gs);
image(box, x0-gs/2 +u, y0 - gs/2 +v, gs, gs);
if (a < xlengths.length - 1){
a += 1;
}
}
else if (u == 1.0E-19){
if (a < xlengths.length - 1){
c += 1;
a += 1;
}
}
}
}
}
Word to the wise: most people aren't going to read that wall of text. Try to "dumb down" your posts so they get to the details right away, without any extra information. You'll also be better off if you post an MCVE instead of only giving us half your code. Note that this does not mean posting your entire project. Instead, start over with a blank sketch and only create the most basic code required to show the problem. Don't include any of your movie logic, and hardcode as much as possible. We should be able to copy and paste your code onto our own machines to run it and see the problem.
All of that being said, I think I understand what you're asking.
How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Separate your program into a view and a model. Right now you're using the screen (the view) to store all of your information, which is going to cause you headaches. Instead, store the state of your program into a set of variables (the model). For you, this might just be a bunch of PVector instances.
Let's say I have an ArrayList<PVector> that holds the current position of all of my vectors:
ArrayList<PVector> currentPositions = new ArrayList<PVector>();
void setup() {
size(500, 500);
for (int i = 0; i < 100; i++) {
currentPositions.add(new PVector(random(width), random(height)));
}
}
void draw(){
background(0);
for(PVector vector : currentPositions){
ellipse(vector.x, vector.y, 10, 10);
}
}
Notice that I'm just hardcoding their positions to be random. This is what your MCVE should do as well. And then in the draw() function, I'm simply drawing each vector. This is like drawing a single frame for you.
Now that we have that, we can create a nextFrame() function that moves the vectors based on the ArrayList (our model) and not what's drawn on the screen!
void nextFrame(){
for(PVector vector : currentPositions){
vector.x += random(-2, 2);
vector.y += random(-2, 2);
}
}
Again, I'm just hardcoding a random movement, but you would be reading these from your file. Then we just call the nextFrame() function as the last line in the draw() function:
If you're still having trouble, I highly recommend posting an MCVE similar to mine and posting a new question. Good luck.
I'm working on a specific layout algorithm to display photos in a unit based grid. The desired behaviour is to have every photo placed in the next available space line by line.
Since there could easily be a thousand photos whose positions need to be calculated at once, efficiency is very important.
Has this problem maybe been solved with an existing algorithm already?
If not, how can I approach it to be as efficient as possible?
Edit
Regarding the positioning:
What I'm basically doing right now is iterating every line of the grid cell by cell until I find room to fit the element. That's why 4 is placed next to 2.
How about keeping a list of next available row by width? Initially the next-available-row list looks like:
(0,0,0,0,0)
When you've added the first photo, it looks like
(0,0,0,0,1)
Then
(0,0,0,2,2)
Then
(0,0,0,3,3)
Then
(1,1,1,4,4)
And the final photo doesn't change the list.
This could be efficient because you're only maintaining a small list, updating a little bit at each iteration (versus searching the entire space every time. It gets a little complicated - there could be a situation (with a tall photo) where the nominal next available row doesn't work, and then you could default to the existing approach. But overall I think this should save a fair amount of time, at the cost of a little added complexity.
Update
In response to #matteok's request for a coordinateForPhoto(width, height) method:
Let's say I called that array "nextAvailableRowByWidth".
public Coordinate coordinateForPhoto(width, height) {
int rowIndex = nextAvailableRowByWidth[width + 1]; // because arrays are zero-indexed
int[] row = space[rowIndex]
int column = findConsecutiveEmptySpace(width, row);
for (int i = 1; i < height; i++) {
if (!consecutiveEmptySpaceExists(width, space[i], column)) {
return null;
// return and fall back on the slow method, starting at rowIndex
}
}
// now either you broke out and are solving some other way,
// or your starting point is rowIndex, column. Done.
return new Coordinate(rowIndex, column);
}
Update #2
In response to #matteok's request for how to update the nextAvailableRowByWidth array:
OK, so you've just placed a new photo of height H and width W at row R. Any elements in the array which are less than R don't change (because this change didn't affect their row, so if there were 3 consecutive spaces available in the row before placing the photo, there are still 3 consecutive spaces available in it after). Every element which is in the range (R, R+H) needs to be checked, because it might have been affected. Let's postulate a method maxConsecutiveBlocksInRow() - because that's easy to write, right?
public void updateAvailableAfterPlacing(int W, int H, int R) {
for (int i = 0; i < nextAvailableRowByWidth.length; i++) {
if (nextAvailableRowByWidth[i] < R) {
continue;
}
int r = R;
while (maxConsecutiveBlocksInRow(r) < i + 1) {
r++;
}
nextAvailableRowByWidth[i] = r;
}
}
I think that should do it.
How about a matrix (your example would be 5x9) where each cell has a value representing the distance from the top left corner (for instance (row+1)*(column+1) [+1 is only necessary if your first row and value are 0]). In this matrix you look for the area which has the lowest value (when summing up the values of empty cells).
A 2nd matrix (or a 3rd dimension of the first matrix) stores the status of each cell.
edit:
int[][] grid = new int[9][5];
int[] filledRows = new int [9];
int photowidth = 2;
int photoheight = 1;
int emptyRowCounter = 0;
boolean photoFits = true;
for(int i = 0; i < grid.length; i++){
for(int m = 0; m < filledRows.length; m++){
if(filledRows[m]-(photoHeight-1) > i || filledRows[m]+(photoHeight-1) < i){
for(int j = 0; j < grid[i].length; j++){
if(grid[i][j] == 0){
for(int k = 0; k < photowidth; k++){
for(int l = 0; k < photoheight){
if(grid[i+l][j+k]!=0){
photoFits = false;
}
}
}
} else{
emptyRowCounter++;
}
}
if(photoFits){
//place Photo at i,j
}
if(emptyRowCounter == 5){
filledRows[i] = 1;
}
}
}
}
In the gif you have above, it turned out nicely that there was a photo (5) that could fit into the gap under (1) and to the left of (2). My intuition suggests we want to avoid creating gaps like that. Here is an idea that should avoid these gaps.
Maintain a list of "open regions", where an open region has a int leftBoundary, an int topBoundary, and an optional int bottomBoundary. The first open region is just the whole grid (leftBoundary:0, topBoundary: 0, bottom: null).
Sort the photos by height, breaking ties by width.
Until you have placed all photos:
Choose the tallest photo (in case of ties, choose the widest of the tallest photos). Find the first open region it can fit in (such that grid.Width - region.leftBoundary >= photo.Width). Place the photo at the top left of this region. When you place this photo, it may span the entire width or height of the region.
If it spans both the width and the height of the region, the region is filled! Remove this region from the list of open regions.
If it spans the width, but not the height, add the photo's height to the topBoundary of the region.
If it spans the height, but not the width, add the photo's width to the leftBoundary of the region.
If it does not span the height or width of the boundary, we are going to conceptually divide this region into two: one region will cover the space directly to the right of this photo (call it rightRegion), and the other region will cover the space below this region (call it belowRegion).
rightRegion = {
leftBoundary = parentRegion.leftBoundary + photo.width,
topBoundary = parentRegion.topBoundary,
bottomBoundary = parentRegion.topBoundary + photo.height
}
belowRegion = {
leftBoundary = 0,
topBoundary = parentRegion.topBoundary + photo.height,
bottomBoundary = parentRegion.bottomBoundary
}
Replace the current region in the list of open regions with rightRegion, and insert belowRegion directly after rightRegion.
You can visualize how this algorithm would work on your example: First, it would sort the photos: (2,3,4,1,5).
It considers 2, which fits into the first region (the whole grid). When it places 2 at the top left, it splits that region into the space directly to the right of 2, and the space below 2.
Then, it considers 3. It considers the open regions in turn. The first open region is to the right of 2. 3 fits there, so that's where it goes. It spans the width of the region, so the region's topBoundary gets adjusted downward.
Then, it considers 4. It again fits in the first open region, so it places 4 there. 4 spans the height of the region, so the region's leftBoundary gets adjusted rightward.
Then, 1 gets put in the 1x1 gap to the right of 4, filling its region. Finally, 5 gets put just below 2.
Good day to all, I am trying to get an enemy boss ship to appear on screen and attack my ship and also dodge my attacks sometimes. So far I have gotten him to attack my ship but hes stays on the edge of the screen. Here is my code :
#pragma strict
// here are public variables for the enemy ship that can be accessed in the inspector
var health:int = 2;
var explosion:GameObject;
var expOrb:GameObject;
var enemyBullet:GameObject;
var expDrop:int = 3;
var hitSound:AudioClip;
var fireRate:float = 2.0;
//heres the private variable counter to keep track of time for fire rate.
private var counter:float = 0.0;
function Update () {
//here we make counter count based on time for the fire rate
counter += Time.deltaTime;
//if the ship goes too far left, we destroy it.
if(transform.position.x < -12){
Destroy(gameObject);
}
//here we shoot 4 bullets if the counter counts higher than the fire rate.
if(counter > fireRate){
var custom1 = Instantiate(enemyBullet, transform.position - Vector3(0.5,0.1,0), Quaternion.Euler(-90,0,0));
var custom2 = Instantiate(enemyBullet, transform.position - Vector3(0.5,0.1,0), Quaternion.Euler(-90,0,0));
var custom3 = Instantiate(enemyBullet, transform.position- Vector3(0.5,0.1,0), Quaternion.Euler(-90,0,0));
var custom4 = Instantiate(enemyBullet, transform.position- Vector3(0.5,0.1,0), Quaternion.Euler(-90,0,0));
//to make the bullets spread, we add extra z velocity to each one to they all move on their own path.
custom1.rigidbody.velocity.z = 3;
custom2.rigidbody.velocity.z = 1;
custom3.rigidbody.velocity.z = -1;
custom4.rigidbody.velocity.z = -3;
counter = 0.0;
}
//end of function update
}
//if a bullet hits the ship, the bullets sends us the hit message to trigger this function to bring down the ships health
function hit () {
health -= 1;
if(health != 0){
if(audio.enabled == true){
audio.PlayOneShot(hitSound);
}
}
if(health <= 0){
onDeath();
}
}
//if health is 0, then this function is triggered to spawn some orbs, spawn the explosion animation object, and destroy itself
function onDeath () {
Instantiate(expOrb,transform.position,Quaternion.Euler(-90,0,0));
expDrop -= 1;
if(expDrop <= 0){
Instantiate(explosion,transform.position,Quaternion.Euler(-90,Random.Range(-180,180),0));
Destroy(gameObject);
}
if(expDrop > 0){
onDeath();
}
}
How do i add the movement aspect to it?
There are many ways to move an object, you can try:
Transform.translate (http://docs.unity3d.com/ScriptReference/Transform.Translate.html)
Modifying transform.position (http://answers.unity3d.com/questions/188998/transformposition.html)
Adding force to it (http://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html)
And many other ways that I may have not known yet.
For a boss in this kind of game, the movement you may want is either random movement or following the player. Both are not hard to achieve.
Random movement: just do a Random.Range(-1, 1) * bossSpeed *
time.deltaTime and apply it to the boss' x position.
Following the player: get the player's x position then make the boss adjust to the position.
Then how to make the boss dodge the player's bullet sometimes? You can make the boss detect if a player's bullet is incoming by adding a collider thats stands in front of it. If a player's bullet collide with it, then random another number (eg. from 0 to 1). Afterwards, you just need to move the boss away if the random number is 1 and don't move the boss when the random number is 0.
G'day All,
My little game has 5 bouncing balls and 1 player. Initially I wrote the code for the bouncing balls first and each ball has a collision detection method:
foreach (Bouncer bouncer in Game.Components) //For each bouncer component in the game...
{
if (bouncer != this)// Don't collide with myself
{
if (bouncer.collisionRectangle.Intersects(this.collisionRectangle))
{
// How far apart of the positions of the top right hand corners of the sprites when they hit?
int deltaX = Math.Abs((int)this.position.X - (int)bouncer.position.X);
int deltaY = Math.Abs((int)this.position.Y - (int)bouncer.position.Y);
// This is the width and height of a sprite so when two sprites touch this is how far the corners are from each other.
int targetWidth = 80;
int targetHeight = 80;
// The following determins the type of collision (vert hit vs horiz hit)
// Because the app is driven by a game based timer the actual amount of sprite overlap when the collision detection occurs is variable.
// This bit of simple logic has a 10 pixel tollerance for a hit.
// If target - delta is > 10 it will be interpreted as overlap in the non-colliding axis.
// If both if statements are triggered it is interpreted as a corner collision resulting in both sprites rebounding back along the original paths.
if (targetWidth - deltaX < 10) // The hit is a side on hit.
{
this.velocity.X *= -1;
}
if (targetHeight - deltaY < 10) // The hit is a vertical hit
{
this.velocity.Y *= -1;
}
this.numberOfCollisions = this.numberOfCollisions + 1;
}
}
}
base.Update(gameTime);
}
Then I added my player component and the wheels fell off. The app compiles OK but when I run it I get an InvalidCastException and the message:
Unable to cast object of type 'Bounce2.Player' to type 'Bounce2.Bouncer'.
I don't want to include the player object in this collision detector.
Is there a way I can enumerate my way through the Bouncer objects and exclude any other objects?
Thanks,
Andrew.
You can use this:
foreach (Bouncer bouncer in Game.Components.OfType<Bouncer>())
Note that you can store the Bouncer instances in other list too.
I am working on a GTK+ application that uses goocanvas to display a graph on screen. I am having problems coming up with a good way to implement drag scrolling.
Currently the app saves the coordinates where the user clicked and then in a "motion-notify" signal callback, does goo_canvas_scroll_to() to the new position. The problem is that drawing is somewhat slow, and with each pixel moved by the mouse, I get the callback invoked once. This makes the drawing lag behind when dragging the graph around.
Is there a good way to do drag scrolling, so it'd appear more smooth and I could skip some of the redraws?
I was able to get something like this working once by starting a 5ms timer when the user presses the mouse button. In the timer I check where the mouse is and decide which way to scroll, including faster scrolling the closer you are to the edge. The result was very smooth scrolling, at least that's what I remember. Here the guts of it, its gtkmm/c++, but you should be able to get the gist of it:
static const int HOT_AREA = 24;
// convert distance into scroll size. The larger the
// value, the faster the scrolling.
static int accel_fn(int dist) {
if (dist > HOT_AREA)
dist = HOT_AREA;
int dif = dist / (HOT_AREA/4);
if (dif <= 0) dif = 1;
return dif;
}
bool scrollerAddin::on_timeout() {
int ptr_x, ptr_y;
o_scroller->get_pointer(ptr_x, ptr_y);
int vp_width = o_scroller->get_width();
int vp_height = o_scroller->get_height();
if (o_scroller->get_hscrollbar_visible())
vp_height -= o_scroller->get_hscrollbar()->get_height();
if (o_scroller->get_vscrollbar_visible())
vp_width -= o_scroller->get_vscrollbar()->get_width();
if (ptr_x < HOT_AREA)
scroll_left(accel_fn(HOT_AREA-ptr_x));
else if (ptr_x > vp_width - HOT_AREA)
scroll_right(accel_fn(ptr_x - (vp_width - HOT_AREA)));
if (ptr_y < HOT_AREA)
scroll_up(accel_fn(HOT_AREA - ptr_y));
else if (ptr_y > vp_height - HOT_AREA)
scroll_down(accel_fn(ptr_y - (vp_height - HOT_AREA)));
return true;
}
The scroll functions merely adjust the appropriate Adjustment object by the argument.