mercoledì 30 ottobre 2013

Vector3, muovere un oggetto > Unity3D


Fondamentale per ogni buon programmatore di videogiochi è capire come funzionano i vettori. Ogni game object nella scena presenta di default il componente Transform, al suo interno tre diversi oggetti di tipo Vector3 sono accessibili per poterne definire posizione, dimensione e grandezza nello spazio. 
function Start () {
    var pos : Vector3 = Vector3(5,5,5);
    pos.x += 15;
    var dim : Vector3 = Vector3(2,2,2);
    var rot : Vector3 = Vector3(90,0,0);
    //assegno i valori al mio gameobject
    transform.position = pos;
    transform.localScale = dim;
    //Passiamo da angoli di Euler a Quaternion
    transform.rotation = Quaternion.FromToRotation(rot, Vector3.up);
}
Vector3 è l’oggetto utilizzato per instanziare un nuovo vettore, questi può essere utilizzato non solo per definire una posizione, ma anche uno spostamento, contenendo informazioni sulla direzione, verso e intensità del movimento. Lo stesso discorso si può applicare anche alla rotazione e alla dimensione del game object, diciamo che in generale un vettore può essere utilizzato per creare delle semplici trasformazioni su di essi. Nell’esempio vediamo come è possibile spostare un oggetto della scena in una direzione, ricordandoci di utilizzare la variabile deltaTime della classe Time, che permette di rendere uniforme il movimento per ogni diverso tipo di processore.
function Update () {
    muovi(Vector3.up, 0.5);
}
function muovi(dir : Vector3, speed : float)
{
    //sfrutto solo il verso del vettore
    //e lo moltiplico per una mia intensità
    dir = dir.normalized * speed;
    transform.position += dir * Time.deltaTime;
}


Matematicamente è possibile calcolare una direzione dati due punti semplicemente effenduandone la differenza, la direzione di questo vettore è la retta passante per i due punti, il verso è diretto verso il punto sottratto e l’intensità è proporzionale alla distranza tra i due punti.

----------------------------------------------------

Preso direttamente dalla mia tesi, ragionamento molto base, utile per chi si avvicina per la prima volta a Unity3D. Per approfondimenti guardare questo link.
For english readers just look at this page: http://docs.unity3d.com/Documentation/Manual/DirectionDistanceFromOneObjectToAnother.html

sabato 19 ottobre 2013

Cutting video with Xuggler > Java

In case someone needs this information, this is how I managed to cut a video with xuggler. I don't wanna waste time explaining how it works since I raccomand reading my other blog post about ffmpeg, I hope the only code can help. The Cutter class needs the path to the video file and two vectors with the start and ends of each cut of the video you want to make.
package it.xuggler.demo;

import java.awt.image.BufferedImage;
import java.io.File;

import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.MediaListenerAdapter;
import com.xuggle.mediatool.MediaToolAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.IAudioSamplesEvent;
import com.xuggle.mediatool.event.IReadPacketEvent;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.mediatool.event.IWriteHeaderEvent;
import com.xuggle.mediatool.event.IWritePacketEvent;
import com.xuggle.mediatool.event.IWriteTrailerEvent;
import com.xuggle.xuggler.Global;

public class Cutter extends MediaListenerAdapter {
 
 //public static double START_POINT = 10.0 * Global.DEFAULT_PTS_PER_SECOND;
 //public static double END_POINT = 25.0 * Global.DEFAULT_PTS_PER_SECOND;
 private String TMP_DIR;
 
 public static void main(String[] args)
 {
  //--> due vettori
  double s[] = new double[3];
  s[0] = 5;
  s[1] = 20;
  s[2] = 46;
  double e[] = new double[3];
  e[0] = 10;
  e[1] = 35;
  e[2] = 55;
  new Cutter(s,e,args[0],"out");
 }
 
 //Devo utilizzare diversi writer, uno per ogni parte del filmato da tagliare
 private IMediaWriter writers[];
 
 public Cutter(double[] starts, double[] ends, String videoPathin, String videoPathout)
 {
  writers = new IMediaWriter[starts.length];
  IMediaReader reader = ToolFactory.makeReader(videoPathin);
  reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);

  TMP_DIR = videoPathout + "_tmp";
  File tmpdir = new File(TMP_DIR);
  tmpdir.mkdir(); //creo una cartella temporanea per salvere i frammenti
  //passo da secondi a nanosecondi
  for(int i = 0; i < starts.length; i++)
  {
   starts[i]*=Global.DEFAULT_PTS_PER_SECOND;
   ends[i]*=Global.DEFAULT_PTS_PER_SECOND;
   writers[i] =  ToolFactory.makeWriter(TMP_DIR+"/p"+i+".flv", reader); //comprende il nome del file
  }
  
  //creazione di un tool che mi taglia il video nei punti scelti
  videoCheck checkPos = new videoCheck(); //videocheck estende MediaToolAdapter
  reader.addListener(checkPos);
  //IMediaWriter writer = ToolFactory.makeWriter(videoPathout+".flv", reader); //comprende il nome del file
  
  boolean updatedS = false;
  boolean updatedE = false;
  
  int rp = 0; //Relative Position, cambia in base allo scorrere delle parti del filmato
  //E' importante che le parti siano disgiunte
  //reader.
  while(reader.readPacket() == null)
  {
   if(!updatedS && (checkPos.timeInMilisec >= starts[rp]))
   {
    System.out.print("\n" + rp);
    updatedS = true; //da un certo punto inizio a convertire
    updatedE = false;
    checkPos.addListener(writers[rp]);
   }
   
   if(!updatedE && (checkPos.timeInMilisec >= ends[rp] ))
   {
    System.out.print("-" + rp);
    updatedE = true; //arrivato ad un certo punto smetto di convertire
    checkPos.removeListener(writers[rp]);
    writers[rp].close();
    rp++; //passo alla prossima parte del filmato
    if(rp == starts.length)
    { //se sono arrivato alla fine
     System.out.print("\nCLOSE\n");
     //writer.close(); //smetto di convertire
    }
    else
     updatedS = false;
   }
  }
  
  String OUT_FILE = videoPathout+".flv";
  //Ottenuti i file separati li riunisco in un unico file
  concatenateVideoFromWriters(OUT_FILE);
  
}

public void concatenateVideoFromWriters(String OUT_FILE)
{
 //Se il frammento è unico allora devo solo spostare e rinominare
 if(writers.length == 1)
 {
  new File(writers[0].getUrl()).renameTo(new File(OUT_FILE));
 }
 else
 {
  //concateno i primi due e proseguo dal terzo
  new MyConcatenateAudioAndVideo().concatenate(writers[0].getUrl(),writers[1].getUrl(),TMP_DIR+"/d1.flv");
  int i;
  for(i = 2; i < writers.length; i++)
   new MyConcatenateAudioAndVideo().concatenate(TMP_DIR+"/d"+(i-1)+".flv",writers[i].getUrl(),TMP_DIR+"/d"+i+".flv");
  //sposto il file
  new File(TMP_DIR+"/d"+(i-1)+".flv").renameTo(new File(OUT_FILE));
 }
 //elimino tutto
 deleteAllFromTmpFolder();
}

public void deleteAllFromTmpFolder()
{
 System.out.print("deleting tmpfile and folder"+ TMP_DIR +" \n");
 File td = new File(TMP_DIR);
 String[] fileslist = td.list();
 for(String fpath : fileslist)
 {
  System.out.print(fpath+" \n");
  new File(TMP_DIR+"/"+fpath).delete(); //elimino i file nella cartella
 }
 td.delete(); //elimino la cartella
}

 class videoCheck extends MediaToolAdapter
{
 //Devono essere millisecondi 
  public Long timeInMilisec = (long) 0;
  public boolean convert = true;
  
  @Override
    public void onVideoPicture(IVideoPictureEvent event)
  {
   timeInMilisec = event.getTimeStamp();  //mi ritorna il preciso istante in MICROsecondi
    //adesso chiamo la superclasse che continua con la manipolazione
 
    if(convert)
   super.onVideoPicture(event);
  }
  
  @Override
   public void onAudioSamples(IAudioSamplesEvent event)
  {
   if(convert)
    super.onAudioSamples(event);
  }
  
  @Override
   public void onWritePacket(IWritePacketEvent event)
  {
   if(convert)
    super.onWritePacket(event);
  }
  
  @Override
   public void onWriteTrailer(IWriteTrailerEvent event)
  {
   if(convert)
    super.onWriteTrailer(event);
  }
  
  @Override
   public void onReadPacket(IReadPacketEvent event)
  {
   if(convert)
    super.onReadPacket(event);
  }
  
  @Override
   public void onWriteHeader(IWriteHeaderEvent event)
  {
   if(convert)
    super.onWriteHeader(event);
  }
}
 
}

Here the MyConcatenateAudioAndVideo class
package it.xuggler.demo;

/*
 * Copyright (c) 2008, 2009 by Xuggle Incorporated.  All rights reserved.
 * 
 * This file is part of Xuggler.
 * 
 * You can redistribute Xuggler and/or modify it under the terms of the GNU
 * Affero General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * Xuggler is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with Xuggler.  If not, see .
 */


import java.io.File;

import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.IMediaViewer;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.MediaToolAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.AudioSamplesEvent;
import com.xuggle.mediatool.event.IAddStreamEvent;
import com.xuggle.mediatool.event.IAudioSamplesEvent;
import com.xuggle.mediatool.event.ICloseCoderEvent;
import com.xuggle.mediatool.event.ICloseEvent;
import com.xuggle.mediatool.event.IOpenCoderEvent;
import com.xuggle.mediatool.event.IOpenEvent;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.mediatool.event.VideoPictureEvent;
import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.IVideoPicture;

import static java.lang.System.out;
import static java.lang.System.exit;

/** 
 * A very simple media transcoder which uses {@link IMediaReader}, {@link
 * IMediaWriter} and {@link IMediaViewer}.
 */

public class MyConcatenateAudioAndVideo
{
  /**
   * Concatenate two files.
   * 
   * @param args 3 strings; an input file 1, input file 2, and an output file.
   */
  
  public static void main(String[] args)
  {
    if (args.length < 3)
    {
      out.println("Concatent two files.  The destination " +
        "format will be guessed from the file extention.");
      out.println("");
      out.println("   ConcatentateTwoFiles   ");
      out.println("");
      out.println(
        "The destination type will be guess from the supplied file extsion.");
      exit(0);
    }

    File source1 = new File(args[0]);
    File source2 = new File(args[1]);
    
    if (!source1.exists())
    {
      out.println("Source file does not exist: " + source1);
      exit(0);
    }

    if (!source2.exists())
    {
      out.println("Source file does not exist: " + source2);
      exit(0);
    }

    concatenate(args[0], args[1], args[2]);
  }

  /**
   * Concatenate two source files into one destination file.
   * 
   * @param sourceUrl1 the file which will appear first in the output
   * @param sourceUrl2 the file which will appear second in the output
   * @param destinationUrl the file which will be produced
   */
  
  public static void concatenate(String sourceUrl1, String sourceUrl2,
    String destinationUrl)
  {
    out.printf("transcode %s + %s -> %s\n", sourceUrl1, sourceUrl2,
      destinationUrl);

    // video parameters

    final int videoStreamIndex = 0;
    final int videoStreamId = 0;
    final int width = 640;
    final int height = 360;

    // audio parameters

    final int audioStreamIndex = 1;
    final int audioStreamId = 0;
    final int channelCount = 2;
    final int sampleRate = 11025; // Hz

    // create the first media reader

    IMediaReader reader1 = ToolFactory.makeReader(sourceUrl1);

    // create the second media reader

    IMediaReader reader2 = ToolFactory.makeReader(sourceUrl2);

    // create the media concatenator

    MediaConcatenator concatenator = new MediaConcatenator(audioStreamIndex,
      videoStreamIndex);

    // concatenator listens to both readers

    reader1.addListener(concatenator);
    reader2.addListener(concatenator);

    // create the media writer which listens to the concatenator

    IMediaWriter writer = ToolFactory.makeWriter(destinationUrl);
    concatenator.addListener(writer);

    // add the video stream

    writer.addVideoStream(videoStreamIndex, videoStreamId, width, height);

    // add the audio stream

    writer.addAudioStream(audioStreamIndex, audioStreamId, channelCount,
      sampleRate);

    // read packets from the first source file until done

    while (reader1.readPacket() == null)
      ;

    // read packets from the second source file until done

    while (reader2.readPacket() == null)
      ;

    // close the writer

    writer.close();
  }
  
  static class MediaConcatenator extends MediaToolAdapter
  {
    // the current offset
    
    private long mOffset = 0;
    
    // the next video timestamp
    
    private long mNextVideo = 0;
    
    // the next audio timestamp
    
    private long mNextAudio = 0;

    // the index of the audio stream
    
    private final int mAudoStreamIndex;
    
    // the index of the video stream
    
    private final int mVideoStreamIndex;
    
    /**
     * Create a concatenator.
     * 
     * @param audioStreamIndex index of audio stream
     * @param videoStreamIndex index of video stream
     */
    
    public MediaConcatenator(int audioStreamIndex, int videoStreamIndex)
    {
      mAudoStreamIndex = audioStreamIndex;
      mVideoStreamIndex = videoStreamIndex;
    }
    
    public void onAudioSamples(IAudioSamplesEvent event)
    {
      IAudioSamples samples = event.getAudioSamples();
      
      // set the new time stamp to the original plus the offset established
      // for this media file

      long newTimeStamp = samples.getTimeStamp() + mOffset;

      // keep track of predicted time of the next audio samples, if the end
      // of the media file is encountered, then the offset will be adjusted
      // to this time.

      mNextAudio = samples.getNextPts();

      // set the new timestamp on audio samples

      samples.setTimeStamp(newTimeStamp);

      // create a new audio samples event with the one true audio stream
      // index

      super.onAudioSamples(new AudioSamplesEvent(this, samples,
        mAudoStreamIndex));
    }

    public void onVideoPicture(IVideoPictureEvent event)
    {
      IVideoPicture picture = event.getMediaData();
      long originalTimeStamp = picture.getTimeStamp();

      // set the new time stamp to the original plus the offset established
      // for this media file

      long newTimeStamp = originalTimeStamp + mOffset;

      // keep track of predicted time of the next video picture, if the end
      // of the media file is encountered, then the offset will be adjusted
      // to this this time.
      //
      // You'll note in the audio samples listener above we used
      // a method called getNextPts().  Video pictures don't have
      // a similar method because frame-rates can be variable, so
      // we don't now.  The minimum thing we do know though (since
      // all media containers require media to have monotonically
      // increasing time stamps), is that the next video timestamp
      // should be at least one tick ahead.  So, we fake it.
      
      mNextVideo = originalTimeStamp + 1;

      // set the new timestamp on video samples

      picture.setTimeStamp(newTimeStamp);

      // create a new video picture event with the one true video stream
      // index

      super.onVideoPicture(new VideoPictureEvent(this, picture,
        mVideoStreamIndex));
    }
    
    public void onClose(ICloseEvent event)
    {
      // update the offset by the larger of the next expected audio or video
      // frame time

      mOffset = Math.max(mNextVideo, mNextAudio);

      if (mNextAudio < mNextVideo)
      {
        // In this case we know that there is more video in the
        // last file that we read than audio. Technically you
        // should pad the audio in the output file with enough
        // samples to fill that gap, as many media players (e.g.
        // Quicktime, Microsoft Media Player, MPlayer) actually
        // ignore audio time stamps and just play audio sequentially.
        // If you don't pad, in those players it may look like
        // audio and video is getting out of sync.

        // However kiddies, this is demo code, so that code
        // is left as an exercise for the readers. As a hint,
        // see the IAudioSamples.defaultPtsToSamples(...) methods.
      }
    }

    public void onAddStream(IAddStreamEvent event)
    {
      // overridden to ensure that add stream events are not passed down
      // the tool chain to the writer, which could cause problems
    }

    public void onOpen(IOpenEvent event)
    {
      // overridden to ensure that open events are not passed down the tool
      // chain to the writer, which could cause problems
    }

    public void onOpenCoder(IOpenCoderEvent event)
    {
      // overridden to ensure that open coder events are not passed down the
      // tool chain to the writer, which could cause problems
    }

    public void onCloseCoder(ICloseCoderEvent event)
    {
      // overridden to ensure that close coder events are not passed down the
      // tool chain to the writer, which could cause problems
    }
  }
}

giovedì 17 ottobre 2013

Rocket Spline [ info and download ]

Hi guys! If everything worked just as planned, today I finally got my degree in computer science (sorta).
As a project I presented a game made in Unity 3.5 called Rocket Spline, the game works for PC windows and Android devices. It's a puzzle game where the user define the path of a rocket by inserting "control points" into the scene.
Download Links

This is my first not-free game on the market, I hope you like it!

venerdì 4 ottobre 2013

Kagero Project Fan Game [>Download Page<]


--------------------------------------------------------
So, what happened? Why did I make so long to finally publish this thing? Well, not really much happened. I tried co contact Jin until now, twitter, email, IA contact form, nothing. I have to thank a lot of kind people that offered me help and translated stuff from italian to japanese, but in the end, a month passed and still no answer. So what now? I'm releasing a game without the permission of the guy who makes the songs!? Yes.
I'll shut everything down eventually, and it's a fan game I'm not making any money from it.
Anyway, you will notice from the trailer that someone really AWESOME did some audio tracks for the game, yes I'm talking about JubyPhonic. I've to thank her for spreading so much the word about my game, I hope people will be aware of my works in the future.

And now some questions and answers:
-What happened to the android version?
Unfortunately I've to wait for Jin permission for that one, since I plan to publish it on google play in the future.
-There will be more songs in the game?
I don't know. My life is kinda busy at the moment, I would really like to put outer science and sunset yesterday in the game, I think it will depends on how much free time I'll have and how many people are really interested in my game.
-What about iOS version of the game?
Sorry guys, I really don't have the money to buy a mac.
-I like you, I like the game, how can I help?
I doubt someone would like me or my game this much. Anyway, I've made some android application in the past and I'll publish some other games in the market in the future. If you like, give them a try. (You know guys, it's really fun pressing ads on my apps for some reason).

This is it. Have fun with my game.