I have written a script that I have attached to Player which upon collecting a Magnet Power-Up, finds all the active GameObjects with a tag Treasure and makes them follow Player.
The thing is that I want all the active Treasure GameObjects not to only follow but actually go towards and collide with the Player so that points are collected.
Below is my code so far, any help is appreciated.
using UnityEngine;
using System.Collections;
public class TreasureFollowPlayer : MonoBehaviour {
public GameObject[] treasures;
public bool magnetPowerUpEnabled = false;
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("Magnetpowerup"))
{
col.gameObject.SetActive(false);
magnetPowerUpEnabled = true;
}
}
// Update is called once per frame
void Update() {
if (magnetPowerUpEnabled)
{
treasures = GameObject.FindGameObjectsWithTag("Treasure");
foreach (var treasure in treasures)
{
treasure.transform.position = Vector2.MoveTowards(treasure.transform.position, transform.position, 1.0f * Time.deltaTime);
}
}
}
}
You will need to ensure the treasure moves faster than the player so it can catch up for starters. Then have a small script either on the treasure or the player which checks for onTriggerEnter calls. When the treasure touches the player then fire off a function destroying or disabling it and increase the players score however is appropriate.
Related
First time writing an AsyncTask and I seem to have a subtle design flaw that prevents both ProgressDialog, ProgressBar, and even Log.d() from working properly. I suspect that somehow I am not actually creating a new thread/task.
Short: the symptoms
A ProgressDialog is created in the constructor, and the code orders Android to show it in onPreExecute(), but the dialog never shows.
onProgressUpdate() is supposed to execute whenever I call publishProgress() from within doInBackground(), correct? Well, it doesn't. Instead, it executes when doInBackground() completes.
Long: investigations
Things I have verified through the emulator and, when possible, on a phone:
onPreExecute() is definitely called
the progress bar is not reset until after doInBackground() completes
update_dialog.show() is definitely executed, but the dialog does not appear unless I remove the .dismiss() in onPostExecute(); I imagine dialog is, like the progress bar, not shown until after doInBackground() completes, but is naturally immediately dismissed
the code will happily show dialogs when no computation is involved
doInBackground() definitely invokes publishProgress()
when it does, onProgressUpdate() does not execute immediately! that is, I have a breakpoint in the function, and the debugger does not stop there until after doInBackground() completes! (perhaps this is a phenomenon of the debugger, rather than doInBackground(), but I observe the same symptoms on a mobile device)
the progress bar gets updated... only after doInBackground() completes everything
similarly, the Log.d() data shows up in Android Monitor only after doInBackground() completes everything
and of course the dialog does not show up either in the emulator or on a device (unless I remove .dismiss() from onPostExecute())
Can anyone help find the problem? Ideally I'd like a working dialog, but as Android has deprecated that anyway I'd be fine with a working progress bar.
Code
Here are the essentials, less the details of computation &c.:
Where I call the AsyncTask from the main thread:
if (searching) { // this block does get executed!
Compute_Task my_task = new Compute_Task(overall_context, count);
my_task.execute(field, count, max_x, max_y);
try { result = my_task.get(); } catch (Exception e) { }
}
The AsyncTask itself:
private class Compute_Task extends AsyncTask<Object, Integer, Integer> {
public Compute_Task(Context context, int count) {
super();
current_positions = 0;
update_dialog = new ProgressDialog(context);
update_dialog.setIndeterminate(true);
update_dialog.setCancelable(false);
update_dialog.setTitle("Thinking");
update_dialog.setMessage("Please wait");
}
protected void onPreExecute() {
super.onPreExecute();
update_dialog.show();
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.setProgress(0);
}
protected void onPostExecute() {
super.onPostExecute();
update_dialog.dismiss();
}
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.incrementProgressBy(1);
Log.d(tag, values[0].toString());
}
protected Integer doInBackground(Object... params) {
Integer result = compute_scores(
(boolean[][]) params[0], (Integer) params[1], (Integer) params[2], (Integer) params[3], 0)
);
return result;
}
public int compute_scores(boolean[][] field, int count, int max_x, int max_y, int level) {
int result, completed = 0;
switch(count) {
// LOTS of computation goes on here,
// including a recursive call where all params are modified
if (level == 0)
publishProgress(++completed);
}
}
ProgressDialog update_dialog;
}
Turns out this is basically the same issue as the one given here. The "fatal" line is this one:
try { result = my_task.get(); } catch (Exception e) { }
Apparently this puts the UI thread into deep sleep. One should not use get() with an AsyncTask unless one is willing to suspend the UI thread. We have to perform a little magic in onPostExecute() instead.
Although it turns out that this was a duplicate, I didn't find it until after I wrote it, because I didn't realize the thread was blocking.
Have tried debugging by using System.out to check whether a method is run or not. The run method executes fine and the radar begins spinning with the robot console displaying Hello. onScannedRobot seems to be never called. Completely out of a clue of how to resolve. In the battle, the robot compiles fine into the game and it definitely is spinning its radar across other bots.
package ke_shen;
import robocode.util.*;
import robocode.*;
import java.util.*;
import java.awt.Color;
import java.awt.geom.Point2D;
//Oldest Scanned Radar
//Functions by spinning until all robots have been scanned
//then begins to scan in the opposite direction until
//all robots have been scanned again
//this minimizes the time in between all robots in the battlefield
//can be scanned, maximizing speed of scanning
public class shen_robot extends AdvancedRobot {
// the use of a linked hash map is deal here to store the enemy
// robot's names (the key)and their respective absolute bearings (thevalue)
static double scanDirection;
static Object sought;
static Object mostDanger = null;
static double distance = 50000;
static int tempindex = 0;
static int mostDangerIndex;
ArrayList<String> names = new ArrayList<String>();
ArrayList<Double> distanceArray = new ArrayList<Double>();
ArrayList<Double> velocityArray = new ArrayList<Double>();
ArrayList<Double> headingArray = new ArrayList<Double>();
public void run() {
setAdjustRadarForRobotTurn(true);
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
setAllColors(Color.BLUE);
System.out.println("Hello.");
scanDirection = 1;
// below, scanDirection will be become either negative or positive
// this changes the direction of the scan from initially
// clockwise to counterclockwise and vice versa;
setTurnRadarRightRadians(scanDirection * Double.POSITIVE_INFINITY);
scan();
// linearTargeting();
// execute();
}
// removes the robot from the hash map when it dies
public void onRobotDeathEvent(RobotDeathEvent e) {
int index = names.indexOf(e.getName());
names.remove(e.getName());
distanceArray.remove(index);
velocityArray.remove(index);
headingArray.remove(index);
}
public void onScannedRobot(ScannedRobotEvent e) {
System.out.println("Helo.");
// RADAR
// the radar will spin in a full circle once in the beginning of the
// battle
// and add all the robots to the hash map
// the second rotation, once it reaches the last robot in the hash map,
// because the radar heading is now greater than the normalRelative
// angle
// scanDirection will become negative, resulting in the radar spinning
// in the other
// direction due to the code above in line 31
// UPDATES PROPERTIES AFTER THE INITIAL 360 degree SCAN
String name = e.getName();
if (names.contains(name) == true) {
tempindex = names.indexOf(name);
headingArray.remove(tempindex);
headingArray.add(tempindex, e.getHeadingRadians());
velocityArray.remove(tempindex);
velocityArray.add(tempindex, e.getVelocity());
distanceArray.remove(tempindex);
distanceArray.add(tempindex, e.getDistance());
}
// HEADING
else {
int index = names.size()-1;
headingArray.add(e.getHeadingRadians());
if (names.size() == getOthers()) {
scanDirection = Utils.normalRelativeAngle(headingArray.get(index) - getRadarHeadingRadians());
}
// VELOCITY
velocityArray.add(e.getVelocity());
// DISTANCE & MOSTDANGEROUS
distanceArray.add(e.getDistance());
}
while (distanceArray.iterator().hasNext()) {
if (distanceArray.iterator().next() < distance) {
distance = distanceArray.iterator().next();
}
}
mostDangerIndex = distanceArray.indexOf(distance);
}
public void addInfo(String name, int number) {
}
}
Trivial Test
Changing OnScannedRobot to this allows it to execute normally. So the robot is catching the on scan events:
public void onScannedRobot(ScannedRobotEvent e) {
System.out.println("Helo.");
}
Diagnose the Problem
The issue is that if a robot fails to complete his turn in the time allotted, the turn will be skipped. Now the question is, what piece of the OnScannedRobot method is time inefficient?
Resolution
As it turns out, the mostDangerIndex calculation (that includes the while loop) is the culprit. So to fix the OnScannedRobot method, I replaced the mostDangerIndex calculation (that includes the while loop) with:
mostDangerIndex = distanceArray.indexOf(Collections.min(distanceArray));
Now it works!
I'm new to Unity and c# and I'm trying to get the basics down but I seem to be having some trouble with the collision. I want to get a falling object to destroy when it collides with another object that is stationary. All of the objects are set to Box Collider 2D in Unity and after hours of searching I can't seem to figure out what's wrong with it. Any help would be much appreciated!
using UnityEngine;
using System.Collections;
public class Destroy : MonoBehaviour {
// Use this for initialization
void Start () {
transform.position = new Vector2 (0, -10);
Debug.Log ("Game Start");
}
// Update is called once per frame
void Update () {
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Target") //|| (col.gameObject.tag == "fallingCube2"))
{
Debug.Log ("There has been a collision!");
Destroy (col.gameObject);
}
else
if (col.gameObject.tag == "otherTarget")
{
Debug.Log ("There has been a collision!");
Destroy (col.gameObject);
}
}
}
Make sure that the Tag is the same (care with uppercase), and use col.tag == "Target".
The GameObject must have and BoxCollider2D or other Collider2D with the property isTrigger to false.
I always use OnTriggerEnter2D(Collider2D col) because I dont want that my pj stops falling or whatever
I have a VideoDisplay instance playing some video. When I click on the video slider (also my component) the property videoDisplay.playheadTime is set and the videoDisplay.state goes from 'playing' into a 'seeking' state for a brief moment (the videoDisplay seeks for a new position and then plays the video again). Intended bevaiour.
But if I'm (or any random user) fast enough, I can set the playheadTime again while the player is still in 'seeking' state. When repeated several times every click is enqueued and the videoDisplay jump on every place of the video I have clicked(this is happening in an interval about 10-15 second after my last click). When I use live dragging the videoDisplay, overwhelmed by seekings, goes into 'error' state.
My question is - is there any way to cancel seeking state of the VideoDisplay class? For example player is in 'seeking' state, I set playheadTime, and the player forgets about last seeking and try to find the new place of the video.
I will downvote pointless answers like 'Use the Flex4 VideoPlayer class'!
One possible way is wrap the video display in a component and manage the seek a little better yourself. So if someone calls seek, make sure that the video is not currently seeking, if so, then wait till the current operation is complete before proceeding to the new one. If the user tries to seek again, discard all currently pending operations and make the latest one the next operation. Working on this exact problem right now.... Here's the code:
public function Seek(nSeconds:Number, bPlayAfter:Boolean):void
{
trace("Player Seek: "+ nSeconds);
var objSeekComand:VideoPlayerSeekCommand = new VideoPlayerSeekCommand(ucPlayer, nSeconds, bPlayAfter);
ProcessCommand(objSeekComand);
}
protected function ProcessCommand(objCommand:ICommand):void
{
if(_objCurrentCommand != null)
{
_objCurrentCommand.Abort();
}
_objCurrentCommand = objCommand
objCommand.SignalCommandComplete.add(OnCommandComplete);
objCommand.Execute();
}
Here's the Command
public class VideoPlayerSeekCommand extends CommandBase
{
private var _ucVideoDisplay:VideoDisplay;
private var _nSeekPoint:Number;
private var _bPlayAfterSeek:Boolean;
private var _bIsExecuting:Boolean;
public function VideoPlayerSeekCommand(ucVideoDisplay:VideoDisplay, nSeekPointInSeconds:Number, bPlayAfterSeek:Boolean, fAutoAttachSignalHandler:Function = null)
{
_ucVideoDisplay = ucVideoDisplay;
_nSeekPoint = nSeekPointInSeconds;
_bPlayAfterSeek = bPlayAfterSeek;
super(fAutoAttachSignalHandler);
}
override public function Execute():void
{
//First check if we are playing, and puase if needed
_bIsExecuting = true;
if(_ucVideoDisplay.playing == true)
{
_ucVideoDisplay.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, OnPlayerStateChangedFromPlay, false, 0, true);
_ucVideoDisplay.pause();
}
else
{
DoSeek();
}
}
protected function OnPlayerStateChangedFromPlay(event:MediaPlayerStateChangeEvent):void
{
_ucVideoDisplay.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, OnPlayerStateChangedFromPlay);
if(_bIsExecuting == true)
{
if(_ucVideoDisplay.playing == false)
{
DoSeek();
}
else
{
throw new Error("VideoPlayerSeekAndPlayCommand - OnPlayerStateChangedFromPlay error");
}
}
}
private function DoSeek():void
{
if(_bIsExecuting == true)
{
_ucVideoDisplay.seek(_nSeekPoint);
CheckSeekComplete();
}
}
private function CheckSeekComplete():void
{
if(_bIsExecuting == true)
{
if (Math.abs( _ucVideoDisplay.currentTime - _nSeekPoint) < 2)
{
if(_bPlayAfterSeek == true)
{
_ucVideoDisplay.play();
}
DispatchAndDestroy();
}
else
{
CoreUtils.CallLater(CheckSeekComplete, .07);
}
}
}
override public function Abort():void
{
_bIsExecuting = false;
SignalCommandComplete.removeAll();
}
}
Im Using AS3 Signals here instead of events, and the CoreUtils.Call later you can use setInterval, or a Timer. But the idea is to not call seek until the video is paused, and to keep track of when the seek is complete.
Please help me fill the question marks. I want to get a feed from my camera and to pass it to the receive function. Also in flash builder(in design mode) how do I put elements so they can play a camera feed?? Because as it seems VideoDisplay just doesn't work
public function receive(???:???):void{
//othercam is a graphic element(VideoDisplay)
othercam.??? = ????;
}
private function send():void{
var mycam:Camera = Camera.getCamera();
//mycam2.attachCamera(mycam);
//sendstr is a stream we send
sendstr.attachCamera(mycam);
//we pass mycam into receive
sendstr.send("receive",mycam);
}
public function receive():void
{
video = new Video(put-width-here, put-height-here);
video.attachCamera(mycam); // mycam needs to be a class variable, not local to "send()";
mybitmap = new BitmapData(fill parameters here);
update();
}
public function update() {
mybitmap.draw(video);
// do stuff to your bitmap here...
}