I'm using Unity 3d version 4 because I have a MacOS X and I'm making a FPS 3D
I have a script to make the player shoot but this script only shoots up and does not consider where I point the mouse
Below the code in CS
Could someone please correct my script because I have been blocked for 3 days and I have not found any solution on the Internet. Thanks
using UnityEngine;
using System.Collections;
public class ShootDemo : MonoBehaviour {
public Rigidbody projectile;
public float speed = 100;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
Rigidbody instantiatedProjectile = Instantiate(projectile,
transform.position,
transform.rotation)
as Rigidbody;
instantiatedProjectile.velocity = transform.TransformDirection(new Vector3(0, 0,speed));
}
}
}
The way you set the velocity is not right, you should get the mouse position like this:
Rigidbody instantiatedProjectile = Instantiate(projectile, transform.position, transform.rotation);
var input = Input.mousePosition;
input.z = 10;
Vector2 touchPos = Camera.main.ScreenToWorldPoint(input);
Vector2 dir = new Vector2(transform.position.x, transform.position.y) - touchPos;
dir.Normalize();
instantiatedProjectile.velocity = dir * speed;
I found this script in JavaSript working but the bullet speed is too slow and then the bullet stays in the scene for 2 seconds instead of making it disappear completely. How can I then add strength to the bullet?
var Effect : Transform;
var TheDamage = 100;
function Update ()
{
var hit : RaycastHit;
var ray : Ray = Camera.main.ScreenPointToRay(Vector3(Screen.width*0.5, Screen.height*0.5, 0));
if (Input.GetMouseButtonDown(0))
{
if (Physics.Raycast (ray, hit, 100))
{
var particleClone = Instantiate(Effect, hit.point, Quaternion.LookRotation(hit.normal));
Destroy(particleClone.gameObject, 2);
hit.transform.SendMessage("ApplyDamage", TheDamage, SendMessageOptions.DontRequireReceiver);
}
}
}
Related
I want to move my boat to the position where i clicked BUT with a realistic movement and rotation :
(http://i.imgur.com/Pk8DOYP.gif)
Here is my code (attached to my boat gameobject) :
Basically, when i click somewhere, it move the boat until it reach the point that i clicked in the first place (i simplified my code for you)
using UnityEngine;
using System.Collections;
public class BoatMovement : MonoBehaviour {
private Vector3 targetPosition;
private float speed = 10f;
private bool isMoving;
void Update(){
if (!isMoving && Input.GetMouseButton (0)) {
targetPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
isMoving = true;
}
if (isMoving) {
moveToPosition ();
}
}
void moveToPosition() {
transform.position = Vector3.MoveTowards (transform.position, new Vector3(targetPosition.x, targetPosition.y, 0f), speed * Time.deltaTime);
if (transform.position.x == targetPosition.x && transform.position.y == targetPosition.y) {
isMoving = false;
}
}
}
After some research and tries, i didn't find a way to do what i want.
Thanks for your help
There's two parts to this problem, which should be kept completely separate from each other and at no time does the equation of one interfere with the equation of the other.
The first is the forward movement of the ship, which can be achieved in two ways:
If you are using a rigidbody
void Propel()
{
float speed = 150f;
RigidBody rb = GetComponent<RigidBody>();
Transform transform = GetComponent<Transform>();
rb.AddForce(transform.forward * speed * Time.deltaTime); // <--- I always forget if its better to use transform.forward or Vector3.forward. Try both
}
If no rigidbody
void Propel()
{
float speed = 150f;
Transform transform = GetComponent<Transform>();
transform.Translate(transform.forward * speed * Time.deltaTime, Space.World);
}
Now the second would be the turning of the ship, which also can be achieved in two ways:
With rigidbody
IEnumerator TurnShip(Vector3 endAngle)
{
float threshold = Single.Epsilon;
float turnSpeed = 150f;
RigidBody rb = GetComponent<RigidBody>();
while (Vecotr3.Angle(transform.forward, endAngle) > threshold)
{
rb.AddTorque(transform.up * turnSpeed * Time.deltaTime);
yield return null;
}
}
Without rigidbody
IEnumerator TurnShip(Vector3 endAngle)
{
float threshold = Single.Epsilon;
float turnSpeed = 150f;
float step = turnSpeed * Time.deltaTime;
while (Vector3.Angle(transform.forward, endAngle) > threshold)
{
newDir = Vector3.RotateTowards(transform.forward, endAngle, step);
transform.rotation = Quaternion.LookRotation(newDir);
yield return null;
}
}
Then of course, the IEnumerators are called like so:
StartCoroutine(TurnShip(new Vector3(12f, 1f, 23f));
Couple things to note:
This is pseudo code, i haven't tested any of it so just know that making it work is up to you, i'm only providing you with the correct path to follow.
All the variables in the beginnings of the methods are meant to be global variables, so declare them where you please.
I've used a Transform called target here, just replace it with the Vector from your mouse click.
public Transform target;
private void Update()
{
transform.position += transform.forward * Time.deltaTime;
Vector3 targetDir = target.position - transform.position;
float step = Time.deltaTime / Mathf.PI;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
transform.rotation = Quaternion.LookRotation(newDir);
}
The key to this is the RotateTowards function and calculating a new vector to look towards on each frame based on the current position.
If your boats have some kind of rotation speed stat then modify the float called step to suit. If they have a speed stat then modify the transform.position += transform.forward * Time.deltaTime with some multiplier.
I guess you'll want to put some conditions in as to when to stop the movement and rotation, perhaps using a coroutine.
Declare
private Vector3 targetPosition;
private float targetDistance;
Then at the start of your move, do :
targetPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
targetDistance = Vector3.Distance(targetPosition, transform.position);
While moving call this : (in your update loop for example)
turnSpeed = 0.062f * targetDistance;
moveSpeed = 35f * targetDistance;
//Important /!\ : you need to add Linear drag on your rigidbody or it will keep adding
RigidBody.AddForce(transform.up * moveSpeed * Time.deltaTime);
var newRotation = Quaternion.LookRotation (transform.position - targetPosition, Vector3.forward);
newRotation.x = 0f;
newRotation.y = 0f;
transform.rotation = Quaternion.Slerp (transform.rotation, newRotation, Time.deltaTime * turnSpeed);
Finally, add a linear drag value to your rigidbody (1 would be ok).
Thanks to maksymiuk who helped me and took a lot of his time trying to figure out a solution.
Generalities : explanations about my program and its functioning
I am working on a photo-retouching JavaFX application. The final user can load several images. When he clicks on the button REVERSE, a Task is launched for each image using an Executor. Each of these Task executes the reversal algorithm : it fills an ArrayBlockingQueue<Pixel> (using add method).
When the final user clicks on the button REVERSE, as I said, these Task are launched. But just after these statements, I tell the JavaFX Application Thread to draw the Pixel of the ArrayBlockingQueue<Pixel> (using remove method).
Thus, there are parallelism and concurrency (solved by the ArrayBlockingQueue<Pixel>) between the JavaFX Application Thread and the Task, and between the Task themselves.
To draw the Pixel of the ArrayBlockingQueue<Pixel>, the JavaFX Application Thread starts an AnimationTimer. The latter contains the previously-mentionned remove method. This AnimationTimer is started for each image.
I think you're wondering yourself how this AnimationTimer can know to what image belongs the Pixel it has removed ? In fact, each Pixel has an attribute writable_image that specifies the image to what it belongs.
My problems
Tell me if I'm wrong, but my program should work. Indeed :
My JavaFX Application Thread is the only thread that change the GUI (and it's required in JavaFX) : the Task just do the calculations.
There is not concurrency, thanks to the BlockingQueue I use (in particular, there isn't possibility of draining).
The AnimationTimer knows to what image belongs each Pixel.
However, it's (obviously !) not the case (otherwise I wouldn't have created this question haha !).
My problem is that my JavaFX Application freezes (first problem), after having drawn only some reversed pixels (not all the pixels). On the last loaded image moreover (third problem).
A detail that could be the problems' cause
But I would need your opinion.
The AnimationTimer of course doesn't draw the reversed pixels of each image directly : this is animated. The final user can see each pixel of an image being reversed, little by little. It's very practical in other algorithms as the creation of a circle, because the user can "look" how the algorithm works.
But to do that, the AnimationTimer needs to read a variable called max. This variable is modified (writen) in... each Task. But it's an AtomicLong. So IF I AM NOT WRONG, there isn't any problem of concurrency between the Task themselves, or between the JavaFX Application Thread and these Task.
However, it could be the problem : indeed, the max's value could be 2000 in Task n°1 (= in image n°1), and 59 in Task n°2 (= in image n°2). The problem is the AnimationTimer must use 2000 for the image n°1, and 59 for the n°2. But if the Task n°1 et n°2 have finished, the only value known by the AnimationTimer would be 59...
Sources
When the user clicks on the button REVERSE
We launch the several Task and start several times the AnimationTimer. CLASS : RightPane.java
WritableImage current_writable_image;
for(int i = 0; i < this.gui.getArrayListImageViewsImpacted().size(); i++) {
current_writable_image = (WritableImage) this.gui.getArrayListImageViewsImpacted().get(i).getImage();
this.gui.getGraphicEngine().executor.execute(this.gui.getGraphicEngine().createTask(current_writable_image));
}
for(int i = 0; i < this.gui.getArrayListImageViewsImpacted().size(); i++) {
current_writable_image = (WritableImage) this.gui.getArrayListImageViewsImpacted().get(i).getImage();
this.gui.getImageAnimation().setWritableImage(current_writable_image);
this.gui.getImageAnimation().startAnimation();
}
The Task are part of the CLASS GraphicEngine, which contains an Executor :
public final Executor executor = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
public Task createTask(WritableImage writable_image) {
int image_width = (int) writable_image.getWidth(), image_height = (int) writable_image.getHeight();
Task ret = new Task() {
protected Void call() {
switch(operation_to_do) {
case "reverse" :
gui.getImageAnimation().setMax(image_width*image_height); // USE OF "MAX" VARIABLE
reverseImg(writable_image);
break;
}
return null;
}
};
return ret;
}
The same CLASS, GraphicEngine, also contains the reversal algorithm :
private void reverseImg(WritableImage writable_image) {
int image_width = (int) writable_image.getWidth(), image_height = (int) writable_image.getHeight();
BlockingQueue<Pixel> updates = gui.getUpdates();
PixelReader pixel_reader = writable_image.getPixelReader();
double[] rgb_reversed;
for (int x = 0; x < image_width; x++) {
for (int y = 0; y < image_height; y++) {
rgb_reversed = PhotoRetouchingFormulas.reverse(pixel_reader.getColor(x, y).getRed(), pixel_reader.getColor(x, y).getGreen(), pixel_reader.getColor(x, y).getBlue());
updates.add(new Pixel(x, y, Color.color(rgb_reversed[0], rgb_reversed[1], rgb_reversed[2], pixel_reader.getColor(x, y).getOpacity()), writable_image));
}
}
}
Finally, here is the code of the CLASS AnimationTimer. There is nothing particular. Note the variable max is used here too (and in the CLASS GraphicEngine : setMax).
public class ImageAnimation extends AnimationTimer {
private Gui gui;
private AtomicLong max, speed, max_delay;
private long count, start;
private WritableImage writable_image;
ImageAnimation (Gui gui) {
this.gui = gui;
this.count = 0;
this.start = -1;
this.max = new AtomicLong(Long.MAX_VALUE);
this.max_delay = new AtomicLong(999_000_000);
this.speed = new AtomicLong(this.max_delay.get());
}
public void setMax(long max) {
this.max.set(max);
}
public void setSpeed(long speed) { this.speed.set(speed); }
public double getMaxDelay() { return this.max_delay.get(); }
#Override
public void handle(long timestamp) {
if (start < 0) {
start = timestamp ;
return ;
}
ArrayList<Pixel> list_sorted_pixels = new ArrayList<>();
BlockingQueue<Pixel> updates = this.gui.getUpdates();
for(Pixel new_pixel : updates) {
if(new_pixel.getWritableImage() == writable_image) {
list_sorted_pixels.add(new_pixel);
}
}
while (list_sorted_pixels.size() > 0 && timestamp - start > (count * this.speed.get()) / (writable_image.getWidth()) && !updates.isEmpty()) {
Pixel update = list_sorted_pixels.remove(0);
updates.remove(update);
count++;
if (update.getX() >= 0 && update.getY() >= 0) {
writable_image.getPixelWriter().setColor(update.getX(), update.getY(), update.getColor());
}
}
if (count >= max.get()) {
this.count = 0;
this.start = -1;
this.max.set(Long.MAX_VALUE);
stop();
}
}
public void setWritableImage(WritableImage writable_image) { this.writable_image = writable_image; }
public void startAnimation() {
this.start();
}
}
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 newbie in Unity. I want rotate my 2D object based on user touch moved (moved finger on the screen). I have this code:
void Update ()
{
if (Input.touches.Length > 0) {
t = Input.GetTouch (0);
if (t.phase == TouchPhase.Moved) {
Vector3 movePos = new Vector3 (t.position.x, t.position.y, 0);
var objectPos = Camera.main.WorldToScreenPoint (transform.position);
var dir = movePos - objectPos;
transform.rotation = Quaternion.Euler (new Vector3 (0f, 0f, Mathf.Atan2 (dir.y, dir.x) * Mathf.Rad2Deg));
}
}
}
This code rotate the object based on user touch but when I touch screen again in another position and do touch move, it will rotate the whole object to the actual touch and then it will do correct object rotation based on touch move.
And I dont´t want rotate the whole object based on touch position but rotate the object only based on touch move. Do you understand me? Can you help me? How should I rewrite my code?
If I understand you, try to use this code below:
private float turnSpeed = 5f;
private Vector2 movement;
void Update()
{
Vector2 currentPosition = transform.position;
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
Vector2 moveTowards = Camera.main.ScreenToWorldPoint(touch.position);
movement = moveTowards - currentPosition;
movement.Normalize();
}
}
float targetAngle = Mathf.Atan2(movement.y, movement.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, 0, targetAngle), turnSpeed * Time.deltaTime);
}
Let me know if is what you want. Also, there is a complete sample here: https://github.com/joaokucera/unity-2d-object-rotation
Look into using deltaPosition instead of position on your touch. That should get you in the right direction.
var movedVector = t.deltaPosition;
Edit:
Here is a possible integration with your existing code. I don't have Unity on this PC so this is entirely untested. The main idea is you are getting a change in the finger position between frames. You then scale that change by move speed, and of course, the change in time between frame renders (delta time).
How the object rotates relative to that information is up to you. I just inserted the logic into your existing code.
float moveSpeed = 2.0f;
void Update ()
{
if (Input.touches.Length > 0) {
t = Input.GetTouch (0);
if (t.phase == TouchPhase.Moved) {
var delta = t.deltaPosition * moveSpeed * Time.deltaTime;
transform.rotation = Quaternion.Euler (new Vector3 (0f, 0f, Mathf.Atan2 (delta .y, delta.x) * Mathf.Rad2Deg));
}
}
}
I have a set of sound clips to be played one after another in a sequence with couple of time interval inbetween.
In my case, its a question - followed by the set of four options.
When I write the below code, all the audop files start together at same time. How can I had time delay inbetween, so that the second clip plays only after the first one is over, and the third one starts playing, only when the second option is over.
I am with Flex AIR AS 3. See code below. Thanks in advance.
private function playCoundClips(): void
{
//set audio clips
var questionClipSource : String = "assets/quiz_voiceovers/" + questionCode + "Q.mp3";
var optionAClipSource : String = "assets/quiz_voiceovers/" + questionCode + "a.mp3";
var optionBClipSource : String = "assets/quiz_voiceovers/" + questionCode + "b.mp3";
var optionCClipSource : String = "assets/quiz_voiceovers/" + questionCode + "c.mp3";
var optionDClipSource : String = "assets/quiz_voiceovers/" + questionCode + "d.mp3";
playThisClip(questionClipSource);
playThisClip(optionAClipSource);
playThisClip(optionBClipSource);
playThisClip(optionCClipSource);
playThisClip(optionDClipSource);
}
private function playThisClip(clipPath : String) : void
{
try
{
clipPlayingNow = true;
var soundReq:URLRequest = new URLRequest(clipPath);
var sound:Sound = new Sound();
var soundControl:SoundChannel = new SoundChannel();
sound.load(soundReq);
soundControl = sound.play(0, 0);
}
catch(err: Error)
{
Alert.show(err.getStackTrace());
}
}
Thanks
Sumit
The problem is you are spawning multiple asynchronous calls. Implement a complete call back function on Sound and then call your playThisClip function inside the callback function. (You can sleep for predefined time before calling)
Time delay, is a very bad idea (in 99% of the case).
Have a look at the SOUND_COMPLETE event (see the doc)
This event is triggered when the sound stops playing.
So, it's now very easy to play sounds in sequence.
A simple example (not tested but idea is here) :
//declare somewhere a list of sounds to play
var sounds:Array=["sound_a.mp3","sound_a.mp3"];//sounds paths
//this function will play all sounds in the sounds parameter
function playSounds(sounds:Array):void{
if(!sounds || sounds.length==0){
//no more sound to play
//you could dispatch an event here
return;
}
var sound:Sound=new Sound();
sound.load(new URLRequest(sounds.pop()));
var soundChannel:SoundChannel = sound.play();
soundChannel.addEVentListener(Event.SOUND_COMPLETE,function():void{
soundChannel.removeEventListener(Event.SOUND_COMPLETE,arguments.callee);
playSounds(sounds);
});
}
This helped me
http://livedocs.adobe.com/flex/3/html/help.html?content=Working_with_Sound_09.html
One need to write code for:
sound.addEventListener(Event.ENTER_FRAME, onEnterFrame);
soundControl.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
private function onEnterFrame(event:Event):void
{
var estimatedLength:int =
Math.ceil(sound.length / (sound.bytesLoaded / sound.bytesTotal));
var playbackPercent:uint =
Math.round(100 * (soundControl.position / estimatedLength));
}
private function onPlaybackComplete(event:Event):void
{
Alert.show("Hello!");
}